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

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

Я пытаюсь развернуть строку, включающую подстановочный знак и набор расширений, указанных в фигурных скобках. Кажется, ничего не работает, как показано в примере ниже. переменная 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"

решение1

Theоболочкарасширяется *только если не заключено в кавычки, любое кавычки останавливает расширение оболочкой.

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

Это работает (давайте используем 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

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

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

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"

Скобка -->Переменная--> Глоб || -->Подтяжка--> Переменная -->Глоб
........ цитируется здесь -->^^^^^^ || оценка ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Значения имен файлов не вызывают проблем с выполнением 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 «Расширенные шаблоны»:

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

Примечание: Имейте в виду, что оба решения (eval и patterns) (как написано) безопасны для имен файлов с пробелами или новыми строками. Но не сработают для с $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объясняет порядок расширения:

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

Связанный контент