Как я могу заставить bash расширить переменную, чтобы передать ее в качестве аргумента?

Я обнаружил странное поведение, которое я не знаю, как обойти.

$ var1=*

$ echo $var1
Audiobooks Downloads Desktop (etc.)

$ ls $var1
Audiobooks:

Downloads:
(etc)

Все кажется в порядке. При объявлении переменная расширяется и все остальное работает. Но посмотрите это:

$ var2=~/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm

$ echo $var2
/home/yajo/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm

$ ls $var2
ls: no se puede acceder a /home/yajo/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm: No existe el fichero o el directorio

$ ls /home/yajo/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm
/home/yajo/rpmbuild/RPMS/noarch/enki-12.10.3-1.fc18.noarch.rpm  /home/yajo/rpmbuild/SRPMS/enki-12.10.3-1.fc18.src.rpm
/home/yajo/rpmbuild/RPMS/noarch/enki-12.10.3-1.fc19.noarch.rpm  /home/yajo/rpmbuild/SRPMS/enki-12.10.3-1.fc19.src.rpm

На этот раз при объявлении расширяется только ~, из-за чего я не могу передать его в качестве аргумента ls. Однако передача той же строки буквально приводит к ожидаемым результатам.

Вопросы:

  • Почему иногда расширяются, а иногда нет?
  • Как имитировать поведение $var1 с $var2?

Спасибо.

Дополнительные примечания:

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


person Yajo    schedule 07.07.2013    source источник
comment
См. Как использовать переменные в скрипте bash?.   -  person tom    schedule 07.07.2013


Ответы (1)


Порядок, в котором оболочка анализирует различные аспекты командной строки, не очевиден, и для подобных вещей это важно.

Во-первых, подстановочные знаки не расширяются при объявлении, они расширяются после подстановки значения переменной (примечание: в этих примерах я буду притворяться, что у меня есть ваша файловая система):

$ var1=*
$ echo "$var1"   # double-quotes prevent additional parsing of the variable's value
*
$ echo $var1     # without double-quotes, variable value undergoes wildcard expansion and word splitting
Audiobooks:

Downloads:
(etc)

Кстати, ~ расширяется при объявлении, что еще больше запутывает:

$ var2=~
$ echo "$var2"   # again, double-quotes let me see what's actually in the variable
/home/yajo

Проблема с ~/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm1 заключается в том, что хотя оболочка выполняет расширение подстановочного знака (*) для значения после подстановки, она не выполняет расширение фигурных скобок ({SRPMS,RPMS/*}), поэтому на самом деле она ищет имена каталогов с фигурными скобками и запятыми в имени... и не находя ни одного.

Лучший способ справиться с этим — сохранить список файлов в виде массива; если вы сделаете это правильно, все будет расширено при объявлении:

$ var2=(~/rpmbuild/{SRPMS,RPMS/*}/enki-*.rpm)
$ echo "${var2[@]}"   # This is the proper way to expand an array into a word list
/home/yajo/rpmbuild/RPMS/noarch/enki-12.10.3-1.fc18.noarch.rpm  etc...

Обратите внимание, что массивы являются расширением bash и не будут работать в простых оболочках POSIX. Поэтому обязательно начинайте свой скрипт с #!/bin/bash, а не #!/bin/sh.

person Gordon Davisson    schedule 07.07.2013