Ich lese Bash-Beispiele über, if
aber einige Beispiele sind in eckigen Klammern geschrieben:
if [ -f $param ]
then
#...
fi
andere mit doppelten eckigen Klammern:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
Was ist der Unterschied?
bash
if-statement
rkmax
quelle
quelle
Antworten:
Einzelne
[]
sind Posix Shell-konforme Zustandstests.Double
[[]]
sind eine Erweiterung des Standards[]
und werden von Bash und anderen Shells (z. B. zsh, ksh) unterstützt. Sie unterstützen zusätzliche Operationen (sowie die Standard-Posix-Operationen). Zum Beispiel:||
anstelle von-o
und Regex Matching mit=~
. Eine ausführlichere Liste der Unterschiede finden Sie im Abschnitt Bash-Handbuch zu bedingten Konstrukten .Verwenden
[]
Sie diese Option, wenn Ihr Skript über mehrere Shells hinweg portierbar sein soll. Verwenden[[]]
Sie diese Option, wenn Sie bedingte Ausdrücke möchten, die von nicht unterstützt werden[]
und nicht portierbar sein müssen.quelle
[[ ]]
(z. B. Bash mit#!/bin/bash
oder#!/usr/bin/env bash
). Skripte, bei denen davon ausgegangen wird, dass / bin / sh solche Erweiterungen unterstützt, funktionieren unter Betriebssystemen wie den jüngsten Debian- und Ubuntu-Versionen, bei denen dies nicht der Fall ist.Verhaltensunterschiede
Getestet in Bash 4.3.11:
POSIX vs Bash Erweiterung:
[
ist POSIX[[
ist eine Bash-Erweiterung¹, die unter https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs dokumentiert istreguläres Kommando gegen Magie
[
ist nur ein regulärer Befehl mit einem seltsamen Namen.]
ist nur ein Argument dafür[
, dass keine weiteren Argumente verwendet werden.Ubuntu 16.04 hat tatsächlich eine ausführbare Datei,
/usr/bin/[
die von coreutils bereitgestellt wird, aber die in bash integrierte Version hat Vorrang.An der Art und Weise, wie Bash den Befehl analysiert, wird nichts geändert.
Insbesondere
<
wird umgeleitet&&
und||
mehrere Befehle verkettet, es werden( )
Unterschalen generiert, sofern sie nicht entkommen\
, und die Worterweiterung erfolgt wie gewohnt.[[ X ]]
ist ein einzelnes Konstrukt, dasX
magisch analysiert werden kann.<
,&&
,||
Und()
sind speziell, und einzelne Wörter aufgespalten Regeln behandelt unterschiedlich.Es gibt auch weitere Unterschiede wie
=
und=~
.In Bashese:
[
ist ein integrierter Befehl und[[
ein Schlüsselwort: /ubuntu/445749/whats-the-difference-between-shell-builtin-and-shell-keyword<
[[ a < b ]]
: lexikographischer Vergleich[ a \< b ]
: Das gleiche wie oben.\
erforderlich oder führt die Umleitung wie bei jedem anderen Befehl durch. Bash-Erweiterung.expr a \< b > /dev/null
: POSIX-Äquivalent², siehe: Wie teste ich Zeichenfolgen für lexikografische Zeichen, die in Bash kleiner oder gleich sind?&&
und||
[[ a = a && b = b ]]
: wahr, logisch und[ a = a && b = b ]
: Syntaxfehler,&&
analysiert als UND-Befehlstrennzeichencmd1 && cmd2
[ a = a -a b = b ]
: äquivalent, aber von POSIX³ veraltet[ a = a ] && [ b = b ]
: POSIX und zuverlässiges Äquivalent(
[[ (a = a || a = b) && a = b ]]
: falsch[ ( a = a ) ]
: Syntaxfehler,()
wird als Subshell interpretiert[ \( a = a -o a = b \) -a a = b ]
: äquivalent, wird jedoch()
von POSIX nicht mehr unterstützt{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX-Äquivalent 5Wortaufteilung und Dateinamengenerierung bei Erweiterungen (split + glob)
x='a b'; [[ $x = 'a b' ]]
: true, Anführungszeichen nicht erforderlichx='a b'; [ $x = 'a b' ]
: Syntaxfehler, erweitert auf[ a b = 'a b' ]
x='*'; [ $x = 'a b' ]
: Syntaxfehler, wenn sich mehr als eine Datei im aktuellen Verzeichnis befindet.x='a b'; [ "$x" = 'a b' ]
: POSIX-Äquivalent=
[[ ab = a? ]]
: true, weil es Pattern Matching macht (* ? [
sind magisch). Wird nicht auf Dateien im aktuellen Verzeichnis erweitert.[ ab = a? ]
:a?
glob erweitert sich. Dies kann je nach den Dateien im aktuellen Verzeichnis wahr oder falsch sein.[ ab = a\? ]
: false, keine Glob-Erweiterung=
und==
sind in beiden gleich[
und[[
, ist aber==
eine Bash-Erweiterung.case ab in (a?) echo match; esac
: POSIX-Äquivalent[[ ab =~ 'ab?' ]]
: false 4 , verliert Magie mit''
[[ ab? =~ 'ab?' ]]
: wahr=~
[[ ab =~ ab? ]]
: true, POSIX- Übereinstimmung für erweiterte reguläre Ausdrücke ,?
nicht global erweitert[ a =~ a ]
: Syntax-Fehler. Kein Bash-Äquivalent.printf 'ab\n' | grep -Eq 'ab?'
: POSIX-Äquivalent (nur einzeilige Daten)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: POSIX-Äquivalent.Empfehlung : immer verwenden
[]
.Für jedes
[[ ]]
Konstrukt, das ich gesehen habe, gibt es POSIX-Entsprechungen .Wenn Sie
[[ ]]
Sie verwenden:[
ist nur ein regulärer Befehl mit einem seltsamen Namen, es handelt sich nicht um eine spezielle Semantik.¹ Inspiriert von dem äquivalenten
[[...]]
Konstrukt in der Korn-Schale² schlägt jedoch für einige Werte von
a
oderb
(wie+
oderindex
) fehl und führt einen numerischen Vergleich durch, wenna
undb
wie Dezimalzahlen aussehen.expr "x$a" '<' "x$b"
arbeitet um beide herum.³ und schlägt auch für einige Werte von
a
oderb
wie!
oder fehl(
.4 in Bash 3.2 und höher und vorausgesetzt, die Kompatibilität mit Bash 3.1 ist nicht aktiviert (wie bei
BASH_COMPAT=3.1
)5 obwohl die Gruppierung (hier mit der
{...;}
Befehlsgruppe, anstelle der(...)
eine unnötige Subshell ausgeführt werden würde) nicht erforderlich ist, da die Operatoren||
und&&
shell (im Gegensatz zu den Operatoren||
und&&
[[...]]
oder den Operatoren-o
/-a
[
) die gleiche Priorität haben. Wäre[ a = a ] || [ a = b ] && [ a = b ]
also gleichwertig.quelle
[]
sollte als Meine Präferenz gelesen werden : Verwenden,[]
wenn Sie nicht die Portabilität verlieren möchten . Wie hier angegeben : Wenn Portabilität / Konformität mit POSIX oder der BourneShell ein Problem darstellt, sollte die alte Syntax verwendet werden. Wenn das Skript andererseits BASH, Zsh oder KornShell erfordert, ist die neue Syntax normalerweise flexibler, aber nicht unbedingt abwärtskompatibel. Ich würde lieber mitgehen,[[ ab =~ ab? ]]
wenn ich kann und keine Bedenken hinsichtlich der Abwärtskompatibilität haben alsprintf 'ab' | grep -Eq 'ab?'
In einzelnen Klammern für den Zustandstest (dh [...]) werden einige Operatoren wie single
=
von allen Shells unterstützt, während die Verwendung des Operators==
von einigen älteren Shells nicht unterstützt wird.In doppelten Klammern für den Zustandstest (dh [...]) gibt es keinen Unterschied zwischen der Verwendung
=
oder==
in alten oder neuen Schalen.Bearbeiten: Ich sollte auch Folgendes beachten: Verwenden Sie in Bash nach Möglichkeit immer doppelte Klammern [[...]], da dies sicherer ist als einfache Klammern. Ich werde anhand des folgenden Beispiels veranschaulichen, warum:
Wenn $ var zufällig null / leer ist, sieht das Skript Folgendes:
das wird dein Skript brechen. Die Lösung besteht darin, entweder doppelte Klammern zu verwenden oder immer daran zu denken, Ihre Variablen in Anführungszeichen zu setzen (
"$var"
). Doppelte Klammern sind eine bessere defensive Codierungspraxis.quelle
[[
ist ein Bash-Schlüsselwort, das dem[
Befehl ähnlich (aber leistungsfähiger als) ist .Sehen
http://mywiki.wooledge.org/BashFAQ/031 und http://mywiki.wooledge.org/BashGuide/TestsAndConditionals
Sofern Sie nicht für POSIX sh schreiben, empfehlen wir
[[
.quelle
Sie können die doppelten eckigen Klammern für die Anpassung der leichten Regex verwenden, z.
if [[ $1 =~ "foo.*bar" ]] ; then
(Solange die von Ihnen verwendete Bash-Version diese Syntax unterstützt)
quelle
Bash Handbuch sagt:
(Der Testbefehl ist identisch mit [])
quelle