Ich sehe, ich kann es tun
$ [ -w /home/durrantm ] && echo "writable"
writable
oder
$ test -w /home/durrantm && echo "writable"
writable
oder
$ [[ -w /home/durrantm ]] && echo "writable"
writable
Ich verwende gerne die dritte Syntax. Sind sie in jeder Hinsicht und für alle Negativ- und Kantenfälle gleichwertig? Gibt es Unterschiede in der Portabilität, z. B. zwischen Bash unter Ubuntu und OS X oder älteren / neueren Bash-Versionen, z. B. vor / nach 4.0, und erweitern beide Ausdrücke auf dieselbe Weise?
shell
posix
test
portability
Michael Durrant
quelle
quelle
[ … ]
vs[[ … ]]
vstest …
gibt es vollständigere Antworten in dieser meist doppelten Frage .Antworten:
[
ist ein Synonym für dentest
Befehl und gleichzeitig ein integrierter und ein separater Befehl. Ist[[
aber ein Bash-Schlüsselwort und funktioniert nur in einigen Versionen. Aus Gründen der Portabilität ist es daher besser, single[]
oder zu verwendentest
quelle
[
ist POSIX eingebaut oder Bash eingebaut?test
und[
gleichermaßen. Wenn eine Shell die Auswertung selbstständig durchführen kann, erspart dies Ihnen einen Prozess und beschleunigt ihn etwas, aber das Ergebnis muss dasselbe sein.[
von POSIX definiert und daher maximal portierbar ist oder nicht, immer noch nicht beantwortet (das scheint der springende Punkt dieser Frage zu sein, wenn ich mich nicht irre)[
undtest
ist POSIX . Es scheint weder "empfohlen" noch zu geben, obwohl der einzige Unterschied (?), Den ich zwischen ihnen feststellen kann, darin besteht, dasstest
"das Argument" - "[als Begrenzer für das Ende von Optionen] nicht erkannt wird" (? - dies impliziert "). - " wird als Argumentationsende anerkannt[
, wofür ich mir sowieso keinen guten Testfall ausdenken kann . Aber ich schweife ab. Benutze was du willst. IMO,[
sieht elegant aus, ist abertest
eindeutig ein Befehl.)Ja, da gibt es Unterschiede. Die tragbarsten sind
test
oder[ ]
. Diese sind beide Teil der POSIX-test
Spezifikation .Das
if ... fi
Konstrukt wird ebenfalls von POSIX definiert und sollte vollständig portierbar sein.Das
[[ ]]
ist einksh
Merkmal, das auch in einigen Versionen vonbash
( allen modernen ), inzsh
und vielleicht in anderen, aber nicht insh
oderdash
oder den verschiedenen anderen einfacheren Schalen vorhanden ist.Also, um Ihre Skripte tragbar, verwenden
[ ]
,test
oderif ... fi
.quelle
bash
undzsh
seit[[
sehr langer Zeit unterstützt (bash
fügte es in den späten 90ern hinzu,zsh
spätestens 2000, und ich wäre überrascht, wenn es jemals an Unterstützung mangelte), so dass es unwahrscheinlich ist, dass Sie auf eine Version von beidem ohne stoßen[[
. Esdash
ist weitaus wahrscheinlicher, auf eine andere POSIX-kompatible Shell (z. B. ) zu stoßen.[[
ist, dass Parametererweiterungen nicht in Anführungszeichen gesetzt werden müssen:[[-f $file]]
event funktioniert, wenn$file
Leerzeichen enthalten sind.[[ $a =~ ^reg.*exp.*$' ]]
Bitte beachten Sie, dass dies
[] && cmd
nicht mit derif .. fi
Konstruktion identisch ist .Manchmal ist sein Verhalten ziemlich ähnlich und Sie können
[] && cmd
stattdessen verwendenif .. fi
. Aber nur manchmal. Wenn Sie mehr als einen Befehl zur Ausführung haben, müssen Sieif .. else .. fi
vorsichtig sein und die Logik überprüfen.Einige Beispiele:
Ist nicht dasselbe wie
Denn wenn dies
ls
fehlschlägt,echo
wird ausgeführt, was mit nicht passieren wirdif
.Ein anderes Beispiel:
ist nicht dasselbe wie
obwohl diese Konstruktion gleich wirkt
Bitte beachten Sie,
;
nachdem Echo wichtig ist und da sein muss.Die obige wiederaufgenommene Aussage können wir also sagen
[] && cmd
== Wenn der erste Befehl erfolgreich ist, führen Sie den nächsten ausif .. fi
== Wenn Bedingung (die auch der Testbefehl sein kann), dann Befehl (e) ausführenAlso für die Portabilität zwischen
[
und[[
verwenden[
nur.if
ist POSIX-kompatibel. Also , wenn Sie wählen zwischen[
undif
wählen bei Ihrer Aufgabe und erwartetes Verhalten suchen.quelle
[ -z "$VAR" ] && { ls file; true; } || echo wiiii
. Es ist etwas ausführlicher, aber immer noch kürzer als dieif...fi
Konstruktion.[
undif
als Stellvertreter, aber sie sind nicht. Es ist eigentlich das&&
, was das ersetztif
.[
Führt einen Code aus und gibt einen Status zurück, ähnlich wiels
undgrep
würde.if
Verzweigt die Ausführung in Abhängigkeit vom Rückgabestatus des Befehls (Anweisung), der nach dem if angegeben wird. Dies kann ein beliebiger Befehl (Anweisung) sein.&&
Führt die nächste Anweisung nur aus, wenn die vorherige, ähnlich wie eine einfache, 0 zurückgibtif..then..fi
.Es ist eigentlich das
&&
, was das ersetztif
, nicht dastest
: Eineif
Anweisung in Shell-Skripten prüft, ob ein Befehl einen "erfolgreichen" (Null) Exit-Status zurückgegeben hat. In Ihrem Beispiel lautet der Befehl[
.Es gibt also tatsächlich zwei Dinge, die Sie hier variieren: den Befehl zum Ausführen des Tests und die Syntax zum Ausführen von Code basierend auf dem Ergebnis dieses Tests.
Testbefehle:
test
ist ein standardisierter Befehl zum Auswerten der Eigenschaften von Zeichenfolgen und Dateien. In Ihrem Beispiel führen Sie den Befehl austest -w /home/durrantm
[
ist ein Alias dieses Befehls, der gleichermaßen standardisiert ist und dessen letztes Argument obligatorisch ist]
, um wie ein Ausdruck in eckigen Klammern auszusehen. Lass dich nicht täuschen, es ist immer noch nur ein Befehl (vielleicht findest du sogar, dass dein System eine Datei mit dem Namen hat/bin/[
)[[
ist eine erweiterte Version des Testbefehls, der in einige Shells integriert ist, jedoch nicht Teil desselben POSIX-Standards ist. Es enthält zusätzliche Optionen, die Sie hier nicht verwendenBedingte Ausdrücke:
&&
Operator ( hier standardisiert ) führt eine logische UND-Operation durch, indem er zwei Befehle auswertet und 0 zurückgibt (was true darstellt), wenn beide 0 zurückgeben; Der zweite Befehl wird nur ausgewertet, wenn der erste Null zurückgibt, sodass er als einfache Bedingung verwendet werden kannif ... then ... fi
Konstrukt ( hier standardisiert ) verwendet die gleiche Methode zur Beurteilung der "Wahrheit", erlaubt jedoch eine zusammengesetzte Liste von Aussagen in derthen
Klausel anstelle des einzelnen Befehls, den ein&&
Kurzschluss bietet, und liefertelif
undelse
Klauseln, die schwer zu schreiben sind mit nur&&
und||
. Beachten Sie, dass die Bedingung in einerif
Anweisung nicht in eckige Klammern eingeschlossen ist .Die folgenden Darstellungen sind also alle gleichermaßen portabel und vollständig äquivalent zu Ihrem Beispiel:
test -w /home/durrantm && echo "writable"
[ -w /home/durrantm ] && echo "writable"
if test -w /home/durrantm; then echo "writable"; fi
if [ -w /home/durrantm ]; then echo "writable"; fi
Zwar sind auch die folgenden gleichwertig, aber aufgrund der Nicht-Standard-Natur weniger portabel
[[
:[[ -w /home/durrantm ]] && echo "writable"
if [[ -w /home/durrantm ]]; then echo "writable"; fi
quelle
Verwenden Sie aus Gründen der Portabilität
test
/[
. Aber wenn Sie die Portabilität nicht benötigen, verwenden Sie sie aus Gründen der Gesundheit von Ihnen und anderen, die Ihr Skript lesen[[
. :)Siehe auch
What is the difference between test, [ and [[ ?
in der BashFAQ .quelle
Wenn Sie Portabilität außerhalb der Bourne-ähnlichen Welt wünschen, dann:
ist das tragbarste. Es funktioniert in Schalen der Bourne
csh
undrc
Familien.ausgegeben würden ,
"writable"
anstattwritable
in Schalen derrc
Familie (rc
,es
,akanga
, wo"
ist nichts Besonderes).würde nicht in Shells von
csh
oderrc
Familien auf Systemen funktionieren, in denen kein[
Befehl vorhanden ist$PATH
(von einigen ist bekannt, dasstest
sie einen[
Alias haben, aber nicht ).Funktioniert nur in Schalen der Bourne-Familie.
Funktioniert nur in
ksh
(woher es stammt)zsh
undbash
(alle 3 in der Bourne-Familie).Keiner würde in der
fish
Shell arbeiten, wo Sie brauchen:oder:
quelle
Mein wichtigster Grund für die Auswahl von entweder
if foo; then bar; fi
oderfoo && bar
ist, ob der Beendigungsstatus des gesamten Befehls wichtig ist.vergleichen Sie:
mit:
Sie könnten denken, dass sie dasselbe tun; Wenn
foo
dies jedoch fehlschlägt (oder falsch ist, abhängig von Ihrer Sichtweise), wird do_baz im ersten Beispiel nicht ausgeführt, da das Skript beendet wurde ... Dieset -e
Shell wird angewiesen, sofort zu beenden, wenn ein Befehl einen falschen Status zurückgibt . Sehr nützlich, wenn Sie Dinge tun wie:Sie möchten nicht, dass das Skript weiter ausgeführt wird, wenn das Skript
cd
aus irgendeinem Grund fehlschlägt.quelle
foo
bricht das Skript in beiden Fällen nicht ab. Dies ist ein Sonderfall fürset -e
(wenn der Befehl als Bedingung ausgewertet wird (links von einigen && / || oder in if / while / until / elsif ... -Zuständen). Inbar
beiden Fällen würde ein Fehler die Shell verlassen.cd /some/directory && rm -rf -- *
odercd /some/directory || exit; rm -rf -- *
(entfernt versteckte Dateien immer noch nicht). Ich persönlich mag es nicht, wenn ich mich nichtset -e
bemühe, richtigen Code zu schreiben.