Ich sehe mir ein Bash-Skript mit folgendem Code an:
#!/bin/sh
set -e # Exit if any command fails
# If multiple args given run this script once for each arg
test $2 && {
for arg in $@
do $0 $arg
done
exit
}
.
.
.
Wie im Kommentar erwähnt, besteht der Zweck darin, "das Skript für jedes Argument auszuführen, wenn es mehr als ein Argument gibt". Ich habe einen Runner-Code, um dies zu testen:
# install-unit
# If multiple args given run this script once for each arg
test $2 && {
echo "\$0: $0"
echo "\$1: $1"
echo "\$2: $2"
echo "test \$2 && is true"
}
test $2 && {
# note this is just a regular bash for loop
# http://goo.gl/ZHpBvT
for arg in $@
do $0 $arg
done
exit
}
echo "running: $1"
was Folgendes ergibt:
sh ❯ ./multiple-run.sh cats and dogs and stuff
$0: ./multiple-run.sh
$1: cats
$2: and
test $2 && is true
running: cats
running: and
running: dogs
running: and
running: stuff
sh ❯ ./multiple-run.sh cats
running: cats
Ich möchte, dass jemand das test $2 && {}
Teil und die exit
eingebaute Shell auspackt. Am Anfang dachte ich, dass das test $2
prüft, ob es mehr Argumente gibt, und vielleicht ist es das, aber es sieht seltsam aus, weil es so aussieht, als gäbe es zwei Ausdrücke getrennt durch das "und" &&
, und ich bin auch nur verwirrt, was zum Teufel das exit
eingebaute tut.
Einfache englische Erklärungen mit Beispielen und Dokumentationsreferenzen sind willkommen :)
Vielen Dank!
Edit: Danke Stéphane Chazelas dafür. Für alle, die durch die Änderung der for-Schleifensyntax verwirrt sind, lesen Sie Nummer 3 in diesem Geekstuff- Artikel. Zusammenfassen:
echo "positional parameters"
for arg do
echo "$arg"
done
echo "\nin keyword"
for arg in "$@"
do echo "$arg"
done
gibt uns:
❯ ./for-loop-positional.sh cats and dogs
positional parameters
cats
and
dogs
in keyword
cats
and
dogs
for arg do
Syntax.Antworten:
Das ist eine falsche Schreibweise:
Ich denke, der Autor wollte überprüfen, ob das zweite Argument eine nicht leere Zeichenfolge war (was nicht mit der Überprüfung identisch ist, ob mehr als ein Argument vorhanden ist, da das zweite Argument übergeben werden könnte, sondern die leere Zeichenfolge ist). .
Eine Kurzform von
Gibt true zurück, wenn
somestring
es sich nicht um die leere Zeichenfolge handelt. (test ''
gibt false zurück,test anythingelse
gibt true zurück (aber Vorsichttest -t
bei einigen Shells, die prüfen, ob stdout stattdessen ein Terminal ist)).Der Autor hat jedoch die Anführungszeichen um die Variable vergessen (tatsächlich für alle Variablen). Dies bedeutet, dass der Inhalt von
$2
dem Operator split + glob unterliegt. Also , wenn$2
enthält Zeichen$IFS
(Leerzeichen, Tabulator und Newline durch Standard) oder glob Zeichen (*
,?
,[...]
), das wird nicht funktionieren.Und wenn
$2
leer ist (wie wenn weniger als 2 Argumente übergeben werden oder das zweite Argument leer ist),test $2
wirdtest
nichttest ''
.test
erhält überhaupt kein Argument (leer oder anderweitig).Zum Glück wird in diesem Fall
test
ohne Argumente false zurückgegeben. Es ist etwas besser alstest -n $2
das, was stattdessen true zurückgegeben hätte (da diestest -n
genauso wäre wietest -n -n
), so dass Code in einigen Fällen zu funktionieren scheint.Um zusammenzufassen:
um zu testen, ob 2 oder mehr Argumente übergeben werden:
oder
um zu testen, ob eine Variable nicht leer ist:
All dies ist zuverlässig in POSIX-Implementierungen von
[
, aber wenn Sie mit sehr alten Systemen arbeiten müssen, müssen Sie möglicherweise verwendenstattdessen für Implementierungen von
[
dieser Drossel auf Werte$var
wie=
,-t
,(
...um zu testen, ob eine Variable definiert ist (dies könnte verwendet werden, um zu testen, ob dem Skript ein zweites Argument übergeben wird, aber die Verwendung
$#
ist viel einfacher zu lesen und idiomatischer):(oder das Äquivalent zum
test
Formular. Die Verwendung des[
Alias für dentest
Befehl ist üblicher).Nun zum Unterschied zwischen
cmd1 && cmd2
undif cmd1; then cmd2; fi
.Beide werden
cmd2
nur ausgeführt, wenn siecmd1
erfolgreich sind. Der Unterschied in diesem Fall besteht darin, dass der Exit-Status der gesamten Befehlsliste der des letzten Befehls ist, der in dem&&
Fall ausgeführt wird (also ein Fehlercode , wenncmd1
nicht true zurückgegeben wird (obwohl dies hier nicht ausgelöst wirdset -e
)), während er sich in befindet In diesemif
Fall ist dies der Wert voncmd2
oder 0 (Erfolg), wenn ercmd2
nicht ausgeführt wird.In Fällen, in denen
cmd1
eine Bedingung verwendet werden soll (wenn der Fehler nicht als Problem anzusehen ist ), ist die Verwendung im Allgemeinen besser,if
insbesondere wenn dies das letzte ist, was Sie in einem Skript tun, da dies den Beendigungsstatus Ihres Skripts definiert. Es sorgt auch für besser lesbaren Code.Die
cmd1 && cmd2
Form wird häufiger als Bedingungen selbst verwendet, wie in:Dies ist in Kontexten der Fall, in denen wir uns um den Exit-Status dieser beiden Befehle kümmern.
quelle
test $2 && some_command
besteht aus zwei Befehlen:test $2
prüft, ob der String nach der Erweiterung des zweiten Arguments ($2
) eine Länge ungleich Null hat, dh er prüft notwendigerweisetest -n $2
([ -n $2 ]
). Beachten Sie, dass, da Sie keine Anführungszeichen verwendet haben$2
,test
Werte mit Leerzeichen erstickt werden. Sie solltentest "$2"
hier verwenden.&&
ist ein Kurzschlussauswertungsoperator, der angibt, dass der Befehl after&&
nur ausgeführt wird, wenn der Befehl vor seinem Erfolg erfolgreich ist, dh den Exit-Code 0 hat. Im obigen Beispielsome_command
wird er also nur ausgeführt, wenn ertest $2
erfolgreich ist, dh wenn die Zeichenfolge nicht ist -zero Länge,some_command
wird dann ausgeführt.quelle
test "$2"
ist immer noch nicht sicher, ob $ 2 ist-n
oder so. Auch Stéphanes Antwort ist richtig, dass dies in erster Linie nur eine schlechte Methode ist. (zBfoo arg1 '' arg3
wird es täuschen zu denken, dass es nur ein Argument gibt.)test "$2"
undtest -n "$2"
in POSIX-kompatiblen Implementierungen von zuverlässig sindtest
. Bei nicht konformentest
s treten bei beiden Probleme auf (wie einige mittest -n
und einige mittest -n =
, die einen Fehler zurückgeben würden). In der Vergangenheittest -t
sollte (und dokumentiert) getestet werden, ob stdout ein Terminal ist, dahertest "$2"
konnte es nicht zuverlässig sein. POSIX hat das geändert. ksh93test -t
testet immer noch, ob stdout ein Terminal ist (für Rückwärtsportabilität), aber nur, wenn dietest
und-t
litteral sind (nicht intest "$2"
odercmd=test; "$cmd" -t
odertest $empty -t
).