Как в zsh использовать раскрытие фигурных скобок для аргумента, содержащего пробелы, полученные из переменной?
например, я хочу переименовать файл с ~/a b/1.txt
на ~/a b/2.txt
.
Я могу сделать это вручную из командной строки, используя раскрытие фигурных скобок (но без использования переменной), используя обратную косую черту, выходя из пробела и не цитируя путь раскрытия фигурных скобок, с помощью:
mv ~/a\ b/{1,2}.txt
Ничего из следующего не работает:
mv '~/a b/{1,2}.txt'
mv "~/a b/{1,2}.txt"
mv $'~/a b/{1,2}.txt'
mv '~/a\ b/{1,2}.txt'
mv "~/a\ b/{1,2}.txt"
mv $'~/a\ b/{1,2}.txt'
Я хочу иметь возможность сделать это со значением переменной, например:
bep='~/a\ b/{1,2}.txt'
set -x
mv "${bep}"
mv ${bep}
mv $bep
set +x
Но это не работает.
zsh сообщает (из-за set -x
), что выполняется следующая команда:
mv '~/a\ b/{1,2}.txt'
Ни изменение кавычек, ни удаление обратной косой черты для выхода из пробела, bep='~/a\ b/{1,2}.txt'
ничего не меняет.
Ни (Q)
, ни какой-либо из флагов расширения параметра (q)
, похоже, не помогают.
Я предполагаю, что мне следует попытаться запретить zsh заключать аргумент в одинарные кавычки, но я не знаю, как это сделать кратко.
Или, может быть, есть какой-то способ включить раскрытие скобок внутри одинарных кавычек.
Или…
Правильная команда — mv ~/'a b'/{1,2}.txt
, цитирующая только тот сегмент, который требует кавычки. (В крайнем случае, нужно экранировать только пробел, но, по моему мнению, цитирование всего сегмента выглядит лучше.) Вы можете сохранить полученные аргументы в массиве: bep=(~/'a b'/{1,2}.txt); mv "${bep[@]}"
справится с задачей без каких-либо дополнительных zsh
-специфичных расширений.
что-то из приведенного ниже вы пытаетесь сделать?
touch a\ b/1.txt
mv a\ b/{1,2}.txt
mv a\ b/{2,1}.txt
ll -r a\ b
total 0
-rw-r--r-- 1 tick talkies 0 12 Jun 18:51 1.txt
drwxr-xr-x 3 tick talkies 96 12 Jun 18:51 ..
drwxr-xr-x 3 tick talkies 96 12 Jun 18:53 .
beb='mv a\ b/{1,2}.txt'
eval $beb
ll a\ b/2.txt
-rw-r--r-- 1 tick talkies 0 12 Jun 18:51 a b/2.txt
Примечание: использование eval обычно не одобряется как возможное введение хитрых команд, но если вы полностью контролируете ситуацию, то это не так.
как всегда, протестируйте/проверьте/перепроверьте весь предложенный/показанный код
eval …
работает, но, если возможно, я бы предпочел сделать что-то более безопасное/более лаконичное/более идиоматическое. Я бы предположил, что существует флаг расширения параметра, расширение параметра, настройка или что-то еще, что каким-то образом выводит значение переменной, не заключая ее в одинарные кавычки, или какой-то способ заставить расширение скобок работать внутри одинарных кавычек. Если в течение недели или около того никто не даст лучшего ответа, я приму ваш ответ. Спасибо.
Очевидно, нет способа обработать раскрытие фигурных скобок в переменной, отличной от eval
, но вы можете избежать этой проблемы, сохранив аргументы для mv
в массиве. В любом случае использование массивов для этого обычно является хорошей практикой:
> bep=(~/a\ b/{1,2}.txt)
> typeset -p bep # typeset -p is a good way to see what's in a variable
typeset -a bep=( '/Users/me/a b/1.txt' '/Users/me/a b/2.txt' )
> ls -l ~/a\ b/*
-rw-r--r-- 1 me staff 0 Jun 12 21:38 1.txt
> mv $bep
> ls -l ~/a\ b/*
-rw-r--r-- 1 me staff 0 Jun 12 21:38 2.txt
Другие формы цитирования также будут работать:
> ar=('~/a b/'{1,2}.txt)
> typeset -p ar
typeset -a ar=( '~/a b/1.txt' '~/a b/2.txt' )
> print -r -- $ar
~/a b/1.txt ~/a b/2.txt
> print -r -- ${~ar}
/Users/me/a b/1.txt /Users/me/a b/2.txt
Расширение ${^...}
ведет себя как раскрытие фигурной скобки. Если исходные значения, которые были в раскрытии фигурных скобок, могут быть в массиве, это вариант:
> sv=(1 2)
> ar=(~/a\ b/${^sv}.txt)
> typeset -p ar
typeset -a ar=( '/Users/me/a b/1.txt' '/Users/me/a b/2.txt' )
Если требуется раскрытие скобок, расширение ${^...}
можно использовать для ограничения того, что передается команде eval
:
> be=`{1,2}`
> ar=(~/a\ b/${^$(eval print -r -- $be)}.txt)
> typeset -p ar
typeset -a ar=( '/Users/me/a b/1.txt' '/Users/me/a b/2.txt' )
Утилита zmv может лучше подойти для решения общей проблемы создания имен файлов до и после. По умолчанию он вызывает mv
, но его можно использовать практически с любой командой. В этом примере будут увеличены числа в наборе имен файлов:
> autoload zmv # can be in ~/.zshrc
> ls f*
f1.txt f22.txt
> zmv '(f)(<->)(.txt)' '${1}$((${2}+1))${3}'
> ls f*
f2.txt f23.txt
относительно «...нет способа обработать раскрытие фигурных скобок в переменной, отличной от eval...» присвоение определения псевдониму является одним из возможных вариантов (не могу сказать, что оно подходит для всех сценариев): alias beb='mv a\ b/{1,2}.txt', затем просто вызовите этот beb, который я также видел (вероятно, использовал) echo 'mv a\ b/{1,2}.txt' > /tmp/beb.cmd source /tmp /beb.cmd
@ticktalk — вау — классные приёмы; никогда раньше не думал об использовании псевдонима таким образом. Однако для наших целей, я думаю, мы можем классифицировать их как «eval
без использования eval
», со многими из тех же компромиссов.
eval
лучше подходит для моих целей по разным причинам, но спасибо за предложение. Это будет полезно и в других обстоятельствах.
Расширение скобок происходит до расширения параметров и расширения тильды. Вы можете принудительно выполнить расширение тильды после расширения параметра, но расширение скобок все равно не будет работать.