Расширение скобок zsh для аргумента, содержащего пробелы, полученные из переменной

Как в 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 заключать аргумент в одинарные кавычки, но я не знаю, как это сделать кратко.

Или, может быть, есть какой-то способ включить раскрытие скобок внутри одинарных кавычек.

Или…

Расширение скобок происходит до расширения параметров и расширения тильды. Вы можете принудительно выполнить расширение тильды после расширения параметра, но расширение скобок все равно не будет работать.

user1934428 13.06.2024 09:43

Правильная команда — mv ~/'a b'/{1,2}.txt, цитирующая только тот сегмент, который требует кавычки. (В крайнем случае, нужно экранировать только пробел, но, по моему мнению, цитирование всего сегмента выглядит лучше.) Вы можете сохранить полученные аргументы в массиве: bep=(~/'a b'/{1,2}.txt); mv "${bep[@]}" справится с задачей без каких-либо дополнительных zsh-специфичных расширений.

chepner 13.06.2024 17:35
Переменные, типы данных и операторы в Python
Переменные, типы данных и операторы в Python
В Python переменные используются как место для хранения значений. Пример переменной формы:
0
2
96
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

что-то из приведенного ниже вы пытаетесь сделать?

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 … работает, но, если возможно, я бы предпочел сделать что-то более безопасное/более лаконичное/более идиоматическое. Я бы предположил, что существует флаг расширения параметра, расширение параметра, настройка или что-то еще, что каким-то образом выводит значение переменной, не заключая ее в одинарные кавычки, или какой-то способ заставить расширение скобок работать внутри одинарных кавычек. Если в течение недели или около того никто не даст лучшего ответа, я приму ваш ответ. Спасибо.
XDR 12.06.2024 20:31

Очевидно, нет способа обработать раскрытие фигурных скобок в переменной, отличной от 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 13.06.2024 23:46

@ticktalk — вау — классные приёмы; никогда раньше не думал об использовании псевдонима таким образом. Однако для наших целей, я думаю, мы можем классифицировать их как «eval без использования eval», со многими из тех же компромиссов.

Gairfowl 14.06.2024 12:46
eval лучше подходит для моих целей по разным причинам, но спасибо за предложение. Это будет полезно и в других обстоятельствах.
XDR 22.06.2024 11:54

Другие вопросы по теме