Ein Mitarbeiter behauptete kürzlich in einer Codeüberprüfung, dass das [[ ]]
Konstrukt [ ]
in Konstrukten wie vorzuziehen sei
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
Er konnte keine Begründung liefern. Ist dort eines?
bash
if-statement
syntax
Leonard
quelle
quelle
[[
Der Code ist gut und klar, aber denken Sie an den Tag, an dem Sie Ihre Scriptworks auf das System mit der Standard-Shell portieren, die nichtbash
oderksh
ist. etc.[
ist hässlicher, umständlich, funktioniert aber wieAK-47
in jeder Situation.Antworten:
[[
hat weniger Überraschungen und ist im Allgemeinen sicherer zu bedienen. Aber es ist nicht portabel - POSIX gibt nicht an, was es tut, und nur einige Shells unterstützen es (neben Bash habe ich gehört, dass ksh es auch unterstützt). Zum Beispiel können Sie tunum zu testen, ob eine Datei vorhanden ist. Aber mit
[
muss man zitieren$b
, weil es das Argument spaltet und Dinge wie erweitert"a*"
(wo[[
es wörtlich genommen wird). Das hat auch damit zu tun, wie[
ein externes Programm sein kann und wie jedes andere Programm seine Argumentation erhält (obwohl es auch ein eingebautes sein kann, aber dann hat es immer noch nicht diese spezielle Behandlung).[[
hat auch einige andere nette Funktionen, wie das Abgleichen von regulären Ausdrücken mit=~
zusammen mit Operatoren, wie sie in C-ähnlichen Sprachen bekannt sind. Hier ist eine gute Seite darüber: Was ist der Unterschied zwischen Test[
und[[
? und Bash-Testsquelle
[[ ]]
aber so interpretiert, dass es dasselbe bedeutet wie[ ]
.#!/bin/sh
,#!/bin/bash
wechsle sie dann jedoch zur Verwendung , sobald ich mich auf eine BASH-spezifische Funktion verlasse, um anzuzeigen, dass sie nicht mehr über die Bourne-Shell portierbar ist.Verhaltensunterschiede
Einige Unterschiede zu Bash 4.3.11:
POSIX vs Bash Erweiterung:
[
ist POSIX[[
ist eine Bash-Erweiterung ¹regulä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 dafür zur
/usr/bin/[
Verfügung gestellt von coreutils , 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,( )
Subshells generiert, sofern dies nicht durchbrochen wird\
, 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 ) ]
: Syntax-Fehler,()
wird als Subshell interpretiert[ \( a = a -o a = b \) -a a = b ]
: äquivalent, aber()
von POSIX nicht mehr unterstützt{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX-Äquivalent⁵Wortteilung 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. 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⁴, 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(
.⁴ 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
)⁵ obwohl die Gruppierung (hier mit der
{...;}
Befehlsgruppe, anstelle der(...)
eine unnötige Subshell ausgeführt wird) 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
[
aus den gleichen Gründen.[[ ]]
bietet weitere Funktionen - Ich schlage vor, dass Sie sich das Advanced Bash Scripting Guide ansehen, um weitere Informationen zu erhalten, insbesondere den Abschnitt mit den erweiterten Testbefehlen in Kapitel 7. Tests .Übrigens wurde, wie der Leitfaden feststellt,
[[ ]]
in ksh88 (der 1988er Version der Korn-Shell) eingeführt.quelle
Von welchem Komparator, Test, Klammer oder Doppelklammer ist der schnellste? ( http://bashcurescancer.com )
quelle
[[
es bringen könnte. Aber dann bin ich ein alter Furz der alten Schule :-)[
undtest
obwohl es auch externe Versionen gibt.PS1=...crazy stuff...
und / oder$PROMPT_COMMAND
); Für diese möchte ich keine spürbare Verzögerung bei der Ausführung des Skripts.apt-get update
wenn es mehr als X Stunden her ist, seit es das letzte Mal ausgeführt wurde. Es ist eine große Erleichterung, wenn man die Portabilität von der bereits zu langen Liste von Einschränkungen für Code weglassen kann.Wenn Sie den Styleguide von Google befolgen möchten :
Test
[
und[[
quelle
[[ -d ~ ]]
gibt jedoch true zurück (was impliziert, dass~
auf erweitert wurde/home/user
). Ich denke, Google hätte präziser schreiben sollen.Eine typische Situation, in der Sie nicht verwenden können,
[[
ist in einem Autotools-Skript configure.ac. Dort haben Klammern eine spezielle und andere Bedeutung, sodass Sietest
anstelle von[
oder[[
- Beachten Sie, dass test und[
dasselbe Programm sind.quelle
[
, als POSIX-Shell-Funktion definiert zu werden?[[]] doppelte Klammern werden unter bestimmten Versionen von SunOS nicht unterstützt und innerhalb von Funktionsdeklarationen vollständig nicht unterstützt von: GNU bash, Version 2.02.0 (1) -release (sparc-sun-solaris2.6)
quelle
Kurz gesagt, [[ist besser, weil es keinen anderen Prozess verzweigt. Keine Klammern oder eine einzelne Klammer ist langsamer als eine doppelte Klammer, da sie einen anderen Prozess verzweigt.
quelle
type [
, um dies zu sehen.[[
im Unterschied zu[
, ist von der Syntax bash Befehlszeilen - Interpreter interpretiert. Versuchen Sie in Bash zu tippentype [[
. unix4linux ist richtig, dass klassische Bourne-Shell-[
Tests zwar einen neuen Prozess zur Bestimmung des Wahrheitswerts auslösen , die[[
Syntax (von ksh durch bash, zsh usw. entlehnt) dies jedoch nicht tut.[
ist sowohl in Bash als auch in Dash (der/bin/sh
in allen von Debian abgeleiteten Linux-Distributionen) integriert.