Ich habe das folgende vereinfachte Bash-Skript
#!/bin/bash
files=("$@")
if [ "X$files" = "X" ]; then
files=$HOME/print/*.pdf;
fi
for file in "${files[@]}"; do
ls "$file";
done
Wenn ich Argumente (Dateinamen) als Parameter übergebe, gibt dieses Skript die richtigen Dateinamen aus. Wenn ich dagegen keine Argumente übergebe, wird es gedruckt
/home/user/print/*.pdf: No such file or directory
Warum werden die Dateinamen in diesem Fall nicht erweitert und wie kann ich das beheben? Beachten Sie, dass ich die Konstrukte files=("$@")
und "${files[@]}"
verwende, weil ich gelesen habe, dass sie den üblichen "files = $ *" vorzuziehen sind.
files=$*
jemals üblich ? Das ist einfach falsch .Antworten:
Sie weisen
files
eine skalare Variable anstelle einer Array- Variablen zu.Im
Sie zuweisen einige Zeichenfolge wie
/home/highsciguy/print/*.pdf
zum$files
Skalar (aka string) variabel.Verwenden:
oder
stattdessen. Die Shell erweitert dieses Globbing-Muster zu einer Liste von Dateipfaden und weist sie jeweils Elementen des
$files
Arrays zu .Die Erweiterung des Globs erfolgt zum Zeitpunkt der Zuordnung.
Sie müssen keine nicht standardmäßigen sh-Funktionen verwenden, und Sie können die Systeme Ihres Systems
sh
anstelle vonbash
hier verwenden, indem Sie sie schreiben:set
ist das"$@"
Array der Positionsparameter zuzuweisen .Ein anderer Ansatz könnte darin bestanden haben, das Globbing-Muster in einer skalaren Variablen zu speichern :
Lassen Sie die Shell den Glob zum Zeitpunkt der
$files
Erweiterung der Variablen erweitern.Da dies
$files
nicht in Anführungszeichen steht (was Sie normalerweise nicht tun sollten), unterliegt seine Erweiterung der Wortaufteilung (die wir hier deaktiviert haben) und der Generierung von Globbing / Dateinamen.Das
*.pdf
wird also auf die Liste der passenden Dateien erweitert. Wenn$HOME
sie jedoch Platzhalterzeichen enthalten, können sie auch erweitert werden, weshalb die Verwendung einer Arrayvariablen immer noch vorzuziehen ist.quelle
Möglicherweise haben Sie Dinge wie
files=$*
undfiles=~/print/*.pdf
in älteren Shells ohne Arrays gesehen und dannls $files
.Eine Variablensubstitution, die nicht in doppelten Anführungszeichen steht, interpretiert den Wert der Variablen als durch Leerzeichen getrennte Liste von Shell-Platzhaltermustern, die durch übereinstimmende Dateinamen ersetzt werden, falls vorhanden. Zum Beispiel, nach
files=~/print/*.pdf
,ls $files
erweitert um so etwas wiels
mit den Argumenten/home/highsciguy/print/bar.pdf
,/home/highsciguy/print/foo.pdf
usw. Im Fallfiles=$*
verkettet diese Zuordnung die an das Skript übergebenen Argumente mit Leerzeichen dazwischen, undls $files
spaltet sie wieder heraus.All dies bricht zusammen, wenn Sie Dateinamen haben, die Leerzeichen oder Globbing-Zeichen enthalten. Deshalb sollten Sie dies nicht auf diese Weise tun. Verwenden Sie stattdessen Arrays.
Beachten Sie, dass
var=(…)
."$files"
ist leer, wennfiles
es sich um ein Array handelt, dessen Element des Index 0 nicht gesetzt ist, oder um eine leere Zeichenfolge. Dies[ "X$foo" = "X" ]
ist auch eine veraltete Methode, um zu testen, ob sie$foo
leer ist: Alle modernen Shells werden[ -n "$foo" ]
korrekt implementiert . In Bash können Sie verwenden[[ -n $foo ]]
.In Shells, die keine Arrays unterstützen, gibt es tatsächlich ein Array: die Positionsparameter für die Shell oder die aktuelle Funktion. Hier brauchen Sie das
files
Array nicht wirklich , tatsächlich wäre es einfacher, die Positionsparameter zu verwenden.quelle