bash, сочетающий расширение по шаблону с расширением скобки


8

Я пытаюсь раскрыть строку, включающую подстановочный знак и набор расширений, указанных в фигурных скобках. Ничто не работает, как показано в примере ниже. переменная firstListрасширяется штраф, но ни один secondList, thirdListили fourthListрасширяется должным образом. Я также пробовал разные версии, evalно ни одна не работает. Любая помощь будет оценена

#!/bin/bash
touch a.ext1
touch b.ext1
firstList='*.ext1'
ls  $firstList
touch a.ext2
touch b.ext2
secondList='*.{ext1,ext2}'
ls $secondList 
ls '$secondList'
ls "$secondList"
thirdList=*.{ext1,ext2}
ls $thirdList  
ls '$thirdList'
ls "$thirdList"
fourthList="*.{ext1,ext2}"
ls $fourthList
ls '$fourthList'
ls "$fourthList"

fwiw eval ls $secondListотлично работает здесь ... что вы пытаетесь достичь?
don_crissti

Вам необходимо проверить порядок расширений bash - расширение фигурных скобок происходит до расширений параметров. Чтобы получить эффект, на который вы надеетесь, вам нужно evalполучить 2-й раунд расширений.
Гленн Джекман


@glennjackman Есть решение без оценки. Посмотрите на второе решение в конце моего ответа .

Ответы:


7

Оболочка расширяется *только тогда , когда расширение не-цитируемым, любая ссылка останавливается оболочкой.

Кроме того, расширение скобки должно быть без кавычек, чтобы быть расширенным оболочкой.

Эта работа (давайте посмотрим на echo, что делает оболочка):

$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

Даже если есть файлы с некоторыми другими именами:

$ touch {a,b}.{ext1,ext2} {c,d}.{ext3,ext4} none
ls
a.ext1  a.ext2  b.ext1  b.ext2  c.ext3  c.ext4  d.ext3  d.ext4  none

$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

Почему это работает?

Важно, чтобы мы понимали, почему это работает. Это из-за порядка расширения. Сначала «Расширение скобок», а затем (последнее) «Расширение пути» (он же glob-расширение).

Brace --> Parameter (variable) --> Pathname

Мы можем отключить «Расширение пути» на мгновение:

$ set -f
$ echo *.{ext1,ext2}
*.ext1 *.ext2

«Расширение пути» получает два аргумента: *.ext1и *.ext2.

$ set +f
$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

Проблема в том, что мы не можем использовать переменную для расширения скобки.
Это было объяснено много раз прежде для использования переменной внутри «расширения скобки»

Чтобы развернуть «Расширение скобок», являющееся результатом «Расширения переменных», необходимо повторно передать командную строку в оболочку с помощью eval.

$ list={ext1,ext2}
$ eval echo '*.'"$list"

Brace -> Variable -> Glob || -> Brace -> Variable -> Glob
........ цитируется здесь -> ^^^^^^ || eval ^^^^^^^^^^^^^^^^^^^^^^^^^

Значения имен файлов не вызывают проблем с выполнением для eval:

$ touch 'a;date;.ext1'
eval echo '*.'"$list"
a;date;.ext1 a.ext1 b.ext1 a.ext2 b.ext2

Но ценность $listможет быть небезопасной. Однако значение $listустанавливается автором сценария. Автор сценария контролирует eval: Просто не используйте внешние значения для $list. Попробуй это:

#!/bin/bash
touch {a,b,c}.ext{1,2}
list=ext{1,2}
eval ls -l -- '*.'"$list"

Лучшая альтернатива.

Альтернативой (без eval) является использование Bash «Extended Patterns» :

#!/bin/bash
shopt -s extglob
list='@(ext1|ext2)'
ls -- *.$list

Примечание. Обратите внимание, что оба решения (eval и pattern) (как написано) безопасны для имен файлов с пробелами или новыми строками. Но потерпит неудачу для $listс пробелами, потому $listчто без кавычек или Eval удаляет кавычки.


Да, расширенная глобализация
Гленн Джекман

2

Рассматривать:

secondList='*.{ext1,ext2}'
ls $secondList 

Проблема в том, что расширение скобки выполняется перед расширением переменной . Это означает, что, как указано выше, расширение скобок никогда не выполняется.

Это связано с тем, что когда bash впервые видит командную строку, фигурных скобок нет. После того, secondListкак расширен, это слишком поздно.

Следующее будет работать:

$ s='*'
$ ls $s.{ext1,ext2}
a.ext1  a.ext2  b.ext1  b.ext2

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

Документация

man bash объясняет порядок расширения:

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.