Ich versuche, eine Zeichenfolge mit einem Platzhalter und einer Sammlung von Erweiterungen in Klammern zu erweitern. Nichts scheint zu funktionieren, wie das folgende Beispiel zeigt. Die Variable firstList
wird problemlos erweitert, aber weder secondList
, thirdList
noch fourthList
wird richtig erweitert. Ich habe auch verschiedene Versionen von ausprobiert, eval
aber keine funktioniert. Für jede Hilfe wäre ich dankbar.
#!/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"
Antwort1
DerHülsewird nur erweitert *
, wenn keine Anführungszeichen gesetzt sind. Jegliche Anführungszeichen verhindern die Erweiterung durch die Shell.
Außerdem muss eine Klammererweiterung frei von Anführungszeichen sein, damit sie von der Shell erweitert werden kann.
So funktioniert es (verwenden wir Echo, um zu sehen, was die Shell macht):
$ 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 das funktioniert?
Es ist wichtig, dass wir verstehen, warum das funktioniert. Es liegt an der Reihenfolge der Erweiterung. Zuerst die „Klammernerweiterung“ und später (die letzte) die „Pfadnamenerweiterung“ (auch bekannt als Glob-Erweiterung).
Brace --> Parameter (variable) --> Pathname
Wir können die „Pfadnamenerweiterung“ für einen Moment ausschalten:
$ 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 bereits viele Male erklärt fürVerwenden einer Variablen innerhalb einer „Klammernerweiterung“
Um eine „Klammernerweiterung“ zu erweitern, die das Ergebnis einer „Variablenerweiterung“ ist, müssen Sie die Befehlszeile mit erneut an die Shell übermitteln eval
.
$ list={ext1,ext2}
$ eval echo '*.'"$list"
Klammer -->Variable--> Globus || -->Befestigen--> Variabel -->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
Der Wert von $list
könnte jedoch unsicher sein. Der Wert von $list
wird jedoch vom Skriptautor festgelegt. Der Skriptautor hat die Kontrolle über eval
: Verwenden Sie einfach keine extern festgelegten Werte für $list
. Versuchen Sie Folgendes:
#!/bin/bash
touch {a,b,c}.ext{1,2}
list=ext{1,2}
eval ls -l -- '*.'"$list"
Eine bessere Alternative.
Eine Alternative (ohne eval) istBash „Erweiterte Muster“ verwenden:
#!/bin/bash
shopt -s extglob
list='@(ext1|ext2)'
ls -- *.$list
Hinweis: Bitte beachten Sie, dass beide Lösungen (eval und patterns) (wie geschrieben) für Dateinamen mit Leerzeichen oder neuen Zeilen sicher sind. Sie schlagen jedoch für ein $list
mit Leerzeichen fehl, weil $list
es nicht in Anführungszeichen steht oder die eval die Anführungszeichen entfernt.
Antwort2
Halten:
secondList='*.{ext1,ext2}'
ls $secondList
Das Problem ist, dassKlammererweiterungerledigtVor variable ErweiterungDas bedeutet, dass im obigen Beispiel nie eine Klammererweiterung durchgeführt wird.
Dies liegt daran, dass Bash beim ersten Betrachten der Befehlszeile keine Klammern sieht. Nachdem secondList
sie erweitert wurde, ist es zu spät.
Folgendes funktioniert:
$ s='*'
$ ls $s.{ext1,ext2}
a.ext1 a.ext2 b.ext1 b.ext2
Hier hat die Befehlszeile Klammern, so dassKlammererweiterungkann als erster Schritt durchgeführt werden. Danach $s
wird der Wert von eingesetzt in (variable Erweiterung), und zuletztPfadnamenerweiterungist durchgeführt.
Dokumentation
man bash
erklärt die Reihenfolge der Erweiterung:
Die Reihenfolge der Erweiterungen ist: Klammernerweiterung, Tilde-Erweiterung, Parameter- und Variablenerweiterung, arithmetische Erweiterung und Befehlsersetzung (von links nach rechts durchgeführt), Worttrennung und Pfadnamenerweiterung.