Присвойте результаты сглаживания переменной в Bash - PullRequest
27 голосов
/ 10 февраля 2012

Мой коллега Райан пришел ко мне с ошибкой в ​​его скрипте Bash, и я обнаружил проблему с этим тестом:

$ mkdir ryan
$ mkdir ryan/smells-bad
$ FOO=ryan/smells-*
$ echo $FOO
ryan/smells-bad
$ touch $FOO/rotten_eggs
touch: cannot touch `ryan/smells-*/rotten_eggs': No such file or directory

Из этого я делаю вывод, что сбои происходят во время команды echo,не когда переменная FOO создана.

У нас есть пара обходных путей, в порядке убывания неблагодарности:

touch `echo $FOO`/rotten_eggs

Или:

pushd
cd $FOO
touch rotten_eggs
popd

Но ни одинудовлетворительна.Я пропускаю трюк?

Ответы [ 4 ]

34 голосов
/ 10 февраля 2012

Проблема в том, что глобус будет расширяться только в том случае, если существует файл "rotten_eggs", поскольку он включен в шаблон глобуса. Вы должны использовать массив.

FOO=( ryan/smells-* )
touch "${FOO[@]/%//rotten_eggs}"

Массив FOO содержит все, что соответствует глобусу. Расширение с использованием% добавляет / rotten_eggs к каждому элементу.

7 голосов
/ 10 февраля 2012

Рассмотрим

for dir in $FOO; do
    touch "$dir/rotten_eggs"
done

Обратите внимание, что это будет touch несколько файлов, если шаблон glob совпадает с несколькими путями.

5 голосов
/ 01 марта 2018

Код, как предполагалось, с результатом глобуса, назначенного переменной, будет выглядеть следующим образом:

$ mkdir ryan
$ mkdir ryan/smells-bad
$ FOO=(ryan/smells-*)
$ echo "${FOO[@]}"
ryan/smells-bad
$ echo "$FOO"
ryan/smells-bad
$ touch "$FOO/rotten_eggs"
$ ls -l "$FOO"
total 0
-rw-r--r-- 1 ryan ryan 0 Mar  1 11:17 rotten_eggs

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

но посмотрите, как глобус может соответствовать более чем одному файлу (следовательно, массив является хорошей идеей)

$ mkdir ryan/clean
$ FOO=(ryan/*)
$ echo "$FOO"
ryan/clean
$ echo "${FOO[@]}"
ryan/clean ryan/smells-bad

В этих случаях присваиваются результаты глоба.к переменной по желанию, а не к переменной, раскрываемой как глобус в точке использования.

Конечно, это означает, что переменная действительно должна всегда использоваться в двойных кавычках "..." в противном случае, если само имя файла(расширение glob) также содержит *, оно будет снова glob.

например

$ touch ryan/'*ea*'
$ FOO=(ryan/*ea*)
$ echo "${FOO[@]}"
ryan/clean ryan/*ea*
$ echo ${FOO[@]}
ryan/clean ryan/clean ryan/*ea*
3 голосов
/ 24 апреля 2016

Я бы сделал это так:

for FOO in ryan/smells-*; do
  touch "$FOO"/rotten_eggs
done

Таким образом $FOO содержит действительное имя каталога, а не шаблон глобуса.Однако, если существует более одного совпадения, оно будет содержать только последнее после цикла, поэтому решение для массива может быть лучше для этого случая.

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