Die Shell wird*
nur erweitert , wenn sie nicht in Anführungszeichen gesetzt ist. Bei Anführungszeichen wird die Erweiterung durch die Shell gestoppt.
Außerdem muss eine Klammererweiterung nicht zitiert werden, um von der Shell erweitert zu werden.
Diese Arbeit (verwenden wir Echo, um zu sehen, was die Shell tut):
$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2
Auch wenn es Dateien mit anderen Namen gibt:
$ 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
Warum funktioniert das?
Es ist wichtig, dass wir verstehen, warum das funktioniert. Es liegt an der Reihenfolge der Expansion. Zuerst die "Brace-Erweiterung" und später (die letzte) "Pathname-Erweiterung" (auch bekannt als Glob-Erweiterung).
Brace --> Parameter (variable) --> Pathname
Wir können "Pathname-Erweiterung" für einen Moment deaktivieren:
$ set -f
$ echo *.{ext1,ext2}
*.ext1 *.ext2
Die "Pfadnamenerweiterung" erhält zwei Argumente: *.ext1
und *.ext2
.
$ set +f
$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2
Das Problem ist, dass wir keine Variable für die Klammererweiterung verwenden können.
Es wurde schon oft erklärt , dass eine Variable in einer "Klammererweiterung" verwendet wird.
Um eine "Klammererweiterung" zu erweitern, die das Ergebnis einer "variablen Erweiterung" ist, müssen Sie die Befehlszeile erneut an die Shell mit senden eval
.
$ list={ext1,ext2}
$ eval echo '*.'"$list"
Klammer -> Variable -> Glob || -> Klammer -> Variable -> Glob
........ hier zitiert -> ^^^^^^ || eval ^^^^^^^^^^^^^^^^^^^^^^^^^^
Werte der Dateinamen bringen kein Ausführungsproblem für eval:
$ touch 'a;date;.ext1'
eval echo '*.'"$list"
a;date;.ext1 a.ext1 b.ext1 a.ext2 b.ext2
Aber der Wert von $list
könnte unsicher sein. Der Wert von $list
wird jedoch vom Skriptschreiber festgelegt. Der Skriptschreiber hat die Kontrolle über eval
: Verwenden Sie nur keine extern festgelegten Werte für $list
. Versuche dies:
#!/bin/bash
touch {a,b,c}.ext{1,2}
list=ext{1,2}
eval ls -l -- '*.'"$list"
Eine bessere Alternative.
Eine Alternative (ohne Auswertung) ist die Verwendung von Bash "Extended Patterns" :
#!/bin/bash
shopt -s extglob
list='@(ext1|ext2)'
ls -- *.$list
Hinweis: Bitte beachten Sie, dass beide Lösungen (Bewertung und Muster) (wie geschrieben) für Dateinamen mit Leerzeichen oder neuen Zeilen sicher sind. Wird aber für ein $list
mit Leerzeichen fehlschlagen , weil $list
nicht zitiert oder die Auswertung die Anführungszeichen entfernt.
eval ls $secondList
funktioniert hier gut ... was versuchst du zu erreichen?