Bash: расширение скобок в сценариях не работает из-за нежелательного выхода - PullRequest
9 голосов
/ 01 июля 2011

Я хочу сделать что-то подобное в bash-скрипте. Я использую bash 4.1.10.

# rm -rf /some/path/{folder1,folder2,folder3}

Хорошо работает (и, как и ожидалось) из самой оболочки. Удаляет 3 нужные папки, оставляя все остальные нетронутыми.

Когда я помещаю это в сценарий, происходит что-то нежелательное. Например, мой скрипт:

#!/bin/bash
set -x
VAR="folder1,folder2,folder3"
rm -rf /some/path/{$VAR}

Когда я выполняю этот скрипт, папки не удаляются.

Я думаю, это связано с тем, что происходит нежелательное цитирование. Вывод из скрипта с использованием #!/bin/bash -x:

rm -rf '/some/path/{folder1,folder2,folder3}'

, что, конечно, не может быть успешным из-за отметок '.

Как мне заставить это работать в моем скрипте?

Ответы [ 9 ]

11 голосов
/ 01 июля 2011

Согласно справочной странице :

Порядок расширений: расширение фигурных скобок, расширение тильды, расширение параметров, арифметических и арифметических операций и подстановка команд (выполняется слева направо), разбиение слов и расширение пути.

Чтобы обойти это, добавьте еще один уровень расширения:

eval "rm -rf /some/path/{$VAR}"
5 голосов
/ 01 июля 2011

Поскольку вы пишете сценарий, нет причин писать сложный в обслуживании код, используя eval трюки

VAR="f1,f2,f3"
IFS=,
set -- $VAR
for f; do
  rm -r "/path/to/$f"
done

или

VAR=( f1 f2 f3 )
for f in "${VAR[@]}"; do 
  rm -r "/path/to/$f"
done
2 голосов
/ 18 мая 2012

Если ваш код можно переставить, вы можете использовать echo и подстановку команд в bash.Как то так:

#!/bin/bash
set -x
VAR=`echo /some/path/{folder1,folder2,folder3}`
rm -rf $VAR
2 голосов
/ 01 июля 2011

Нет, это связано с тем, что расширение скобки происходит перед расширением параметра.Найдите другой способ сделать это, например, с помощью xargs.

xargs -d , -I {} rm -rf /some/path/{} <<< "$VAR"
1 голос
/ 25 января 2013

Вам необходимо включить флаг braceexpand:

#!/bin/bash
set -B
for i in /some/path/{folder1,folder2,folder3}
do
  rm -rf "$i"
done
0 голосов
/ 08 февраля 2013

Еще один прием, который вы можете использовать (вместо опасного eval) - это просто echo внутри подоболочки. Это работает, например:

paths=`echo /some/path/{folder1,folder2,folder3}`
echo rm -rf $paths

выходы:

rm -rf /some/path/folder1 /some/path/folder2 /some/path/folder3

по желанию. (Удалите «echo» во второй строке, чтобы заставить его действительно делать rm.)


Важным моментом является то, что bash выполняет расширение скобок перед расширением параметра , поэтому вы никогда не захотите помещать разделенный запятыми список (заключенный в фигурные скобки или нет) в переменную - если вы это сделаете, то вам придется прибегнуть к eval. Однако вы можете поместить список разделенных пробелами строк в переменную, выполнив раскрытие фигурной скобки в подоболочке перед присваиванием .

0 голосов
/ 01 июля 2011

заменить {$VAR} на ${VAR}: -)

0 голосов
/ 01 июля 2011

Проблема не в том, что в режиме сценария происходит какое-то нежелательное цитирование , а в том, что вы помещаете имена папок в переменную, а содержимое переменной раскрывается после расширение скобки выполнено .
Если вы действительно хотите сделать это, вы должны использовать eval:

eval "rm -rf /some/path/{$VAR}"
0 голосов
/ 01 июля 2011
#!/bin/bash
set -x
VAR="folder1,folder2,folder3"
eval "rm -rf /some/path/{$VAR}"

Редактировать Остальное только для информации. Я стараюсь быть информативным, но не многословным: _)

Последние удары имеют опцию globstar. Это может пригодиться в будущем

shopt -s globstar
rm -rfvi some/**/folder?
...