Wann sind in einer Bash if-Anweisung eckige Klammern erforderlich?

74

Normalerweise verwende ich eckige Klammern in der if-Anweisung:

if [ "$name" = 'Bob' ]; then ...

Wenn ich jedoch überprüfe, ob dies greperfolgreich war, verwende ich keine eckigen Klammern:

if grep -q "$text" $file ; then ...

Wann sind die eckigen Klammern in der ifAnweisung erforderlich ?

Mischa Moroshko
quelle
1
Einzelne eckige Klammern sind über mehrere Schalen hinweg kompatibel. Einige von ihnen, einschließlich Bash, unterstützen jedoch die bevorzugte doppelte eckige Klammer. Weitere Informationen finden Sie unter BashFAQ / 031 . Siehe auchhelp '['
Bis auf weiteres angehalten.

Antworten:

124

Die eckigen Klammern sind ein Synonym für den testBefehl. Eine ifAnweisung überprüft den Exit-Status eines Befehls, um zu entscheiden, welcher Zweig verwendet werden soll. grep -q "$text"ist ein Befehl, aber "$name" = 'Bob'nicht - es ist nur ein Ausdruck. testist ein Befehl, der einen Ausdruck nimmt und auswertet:

if test "$name" = 'Bob'; then ...

Da eckige Klammern ein Synonym für den testBefehl sind, können Sie ihn als Ihre ursprüngliche Anweisung umschreiben:

if [ "$name" = 'Bob' ]; then ...
chepner
quelle
2
@chepner: Warum werden if $boolean_var ; then ...keine Klammern benötigt?
Mischa Moroshko
10
@misha, wenn Ihr $boolean_varden Wert "true" oder "false" hat, funktioniert es, weil Sie den Befehl true oder ausführen false.
Glenn Jackman
4
if $boolean_var ; then ...funktioniert nicht, wenn $ boolean_var 0oder ist 1, siehe man trueund man false.
derFunk
@derFunk: Es würde funktionieren , wenn Sie zufällig haben 0und 1Befehle in $PATH- aber das wäre hässlich.
Keith Thompson
Die Rechtschreibprüfung mag die Klammern nicht, funktioniert jedoch mit der Testanweisung in VSCode.
Johnrubythecat
32

[ist eigentlich ein Befehl, der dem Befehl entspricht (fast siehe unten) test. Es ist nicht Teil der Shell-Syntax. (Beide [und test, abhängig von der Shell, sind häufig auch integrierte Befehle, aber das hat keinen Einfluss auf ihr Verhalten, außer vielleicht auf die Leistung.)

Eine ifAnweisung führt einen Befehl aus und führt das thenTeil aus, wenn der Befehl erfolgreich ist, oder das elseTeil (falls vorhanden), wenn es fehlschlägt. (Ein Befehl ist erfolgreich, wenn er mit einem Status ( $?) von 0 beendet wird. Er schlägt fehl, wenn er mit einem Status ungleich Null beendet wird.)

Im

if [ "$name" = 'Bob' ]; then ...

Der Befehl lautet

[ "$name" = 'Bob' ]

(Sie können denselben Befehl direkt ausführen, ohne das if.)

Im

if grep -q "$text" $file ; then ...

Der Befehl lautet

grep -q "$text" $file

man [oder man testfür weitere Informationen.

Fußnote: Nun, der [Befehl entspricht fast dem testBefehl. Der Unterschied besteht darin, [dass dies ]als letztes Argument erforderlich ist und testnicht - und tatsächlich nicht zulässt (genauer gesagt, testbehandelt ein ]Argument nicht speziell; es könnte beispielsweise ein gültiger Dateiname sein). (Es dauerte nicht haben , um auf diese Weise umgesetzt werden, aber eine [ohne passende ]würde eine Menge Leute sehr , sehr nervös gemacht haben.)

Keith Thompson
quelle
Die Rechtschreibprüfung mag die Klammern nicht, funktioniert jedoch mit der Testanweisung in VSCode.
Johnrubythecat
1
@ Johnrubythecat: Auf welche "Rechtschreibprüfung" beziehen Sie sich? Wenn es sich um eine Rechtschreibprüfung für englischen Text handelt, wird es natürlich nicht glücklich über die Shell-Syntax sein.
Keith Thompson
plus eins für das nervousArgument.
Timo
10

Der beste Weg, um an die [ ... ]Syntax zu denken , ist [, sich als Programm zu betrachten - was es ist!

Überprüfen Sie dies heraus:

~ $ ls /usr/bin/\[ 
/usr/bin/[

Auf der anderen Seite verwenden Sie diese Version wahrscheinlich nicht, da sie bashauch [als integrierte Shell bereitgestellt wird.

ifUm Ihre Frage zu beantworten: Führen Sie den Befehl aus, den Sie ihm geben, und sehen Sie, ob der Rückgabewert ist 0oder nicht. Sie verwenden [andere, interessantere Vergleiche, z. B. Zeichenfolgenvergleiche. Siehe man [und man bash.

cha0site
quelle
Es gibt nichts in der Bash-Manpage, was darauf hinweist, dass [es intern implementiert ist. Ich denke, das ist es, wofür es [[ist.
PhilHibbs
@PhilHibbs: Ich bin mir ziemlich sicher, dass [es ein eingebautes ist. Deshalb builtin [funktioniert. [[ist etwas anders als [es macht verschiedene Dinge.
Cha0site
@PhilHibbs: Schauen Sie unter dem Abschnitt SHELL BUILTIN COMMANDS der bashManpage nach. test exprund [ expr ]sind zusammen aufgeführt.
Chepper
1
@ PhilHibbs: Versuchen Sie auchtype -a [
Keith Thompson