Das ist ziemlich kompliziert.
Bitte beachten Sie, dass das Globbing im Inneren nicht funktioniert [[ ]]
. Wenn du sowas rennst
set -x; [[ / == /* ]]; echo $?
dann wirst du sehen /*
wie dort nicht expandiert echo /*
.
Jetzt gibt es eine extglob
Shell-Option. Es sieht so aus, als wäre es in Ihrem Fall in interaktiven Shells aktiviert, in nicht interaktiven deaktiviert. (Compare Wo ist bashs "shopt extglob" für meine interaktive Shell aktiviert? )
Wenn die
extglob
Shell-Option mithilfe des integriertenshopt
Befehls aktiviert wird, werden mehrere erweiterte Musteranpassungsoperatoren erkannt. […]
!(pattern-list)
Entspricht nichts außer einem der angegebenen Muster.
( Quelle )
[[ ]]
Der Bediener wird im Inneren erkannt, erweitert sich jedoch nicht. Wie soll ich wissen? Ich kann die Shell dazu bringen, sie nicht zu erkennen:
shopt -u extglob set -x; [[ !(-z "") ]]; echo $?
Jetzt bekomme ich -bash: !: event not found
. Dies weist auf !
eine andere Bedeutung hin:
!
Starten Sie eine Verlaufsersetzung, es sei denn, es folgt ein Leerzeichen, eine Registerkarte, das Ende der Zeile=
oder(
(wenn dieextglob
Shell-Option mithilfe des integriertenshopt
Befehls aktiviert ist).
( Quelle )
Dies unterscheidet sich zwischen interaktiven und nicht interaktiven Shells:
Wenn die Shell interaktiv ausgeführt wird, ändert sich ihr Verhalten auf verschiedene Arten.
[…]
7. Der Befehlsverlauf […] und die Erweiterung des Verlaufs […] sind standardmäßig aktiviert.
( Quelle )
Der nächste Schritt ist das Deaktivieren des Verlaufs:
shopt -u extglob set +o history set -x; [[ !(-z "") ]]; echo $?
Und hier ist das Ergebnis wie in Ihrer nicht interaktiven Shell.
Können wir das andersherum machen? Können wir eine nicht interaktive Shell dazu bringen, sich wie eine interaktive Shell zu verhalten?
Zuerst schauen wir uns an, was passiert, wenn eine neue Shell interaktiv sein muss:
bash -ic 'set -x; [[ !(-z "") ]]; echo $?'
Es verhält sich wie erwartet, wie Ihre interaktive Shell. Lassen Sie uns jetzt extglob
für eine nicht interaktive Shell aktivieren :
bash -c 'shopt -s extglob; set -x; [[ !(-z "") ]]; echo $?'
Und es geht nicht! Es verhält sich immer noch wie Ihre nicht interaktive Shell mit extglob
deaktivierter. Die Erklärung ist einfach, aber nicht naheliegend: Das Globbing wird für die gesamte Zeile ausgeführt, bevor shopt
es seine Aufgabe erfüllt. Wenn die Option geändert wird, ist es bereits zu spät. Dann teilen wir den Befehl in zwei Zeilen auf:
bash -c 'shopt -s extglob set -x; [[ !(-z "") ]]; echo $?'
Jetzt verhält es sich wie Ihre interaktive Shell.
Das letzte Rätsel ist folgendes:
+ [[ -n !(-z ) ]]
Woher -n
kommen Sie in Ihrer interaktiven Shell? Meine Hypothese basiert auf der Beobachtung, [[ "random-string" ]]
die als behandelt wird [[ -n "random-string" ]]
(überprüfen Sie es mit set -x
). Ich schätze, wenn Sie laufen [[ !(-z "") ]]
und extglob
aktiviert sind, führt die Tatsache, dass der !( )
Operator erkannt, aber nicht erweitert wird, dazu, dass die gesamte !(-z "")
Zeichenfolge dort als ein Wort verbleibt, dh Ihr Befehl wird zu etwas
set -x; [[ "!(-z )" ]]; echo $?
Dieser Befehl (in interaktiver oder nicht interaktiver Shell) verhält sich wie der Befehl, den Sie in der interaktiven Shell ausführen.