Der folgende Befehl funktioniert beispielsweise nicht:
if [[-e xyz]]; then echo File exists;fi
ksh gibt den folgenden Fehler aus
[[-e: command not found
Liegt das daran, dass "[[-" nicht eindeutig ist?
Der folgende Befehl funktioniert beispielsweise nicht:
if [[-e xyz]]; then echo File exists;fi
ksh gibt den folgenden Fehler aus
[[-e: command not found
Liegt das daran, dass "[[-" nicht eindeutig ist?
Antworten:
Die einfachste Erklärung wäre, weil es im Handbuch so aussieht, als müsste [[ expression ]]
zwischen [[
und expression
und Schließen ein Leerzeichen sein ]]
. Aber natürlich können wir versuchen, es genauer zu betrachten. Muscheln haben eine etwas komplexe Grammatik und stützen sich stark auf das Konzept der "Wortteilung". Im Handbuch von ksh (1) heißt es insbesondere:
Die Shell beginnt, ihre Eingabe zu analysieren, indem sie sie in Wörter zerlegt. Wörter, bei denen es sich um Zeichenfolgen handelt, werden durch nicht zitierte Leerzeichen (Leerzeichen, Tabulator und Zeilenumbruch) oder Metazeichen (<,>, |,;, &, (und)) begrenzt. Abgesehen von der Begrenzung von Wörtern werden Leerzeichen und Tabulatoren ignoriert, während Zeilenumbrüche normalerweise Befehle begrenzen.
Wie im Handbuch angegeben, wird die Zeichenfolge [[-e
als Shell-Wort betrachtet. ksh
würde nach einem solchen Befehl in der Liste der eingebauten und speziellen Operatoren (wie for
oder while
) suchen und dann nach einem externen Befehl suchen - und voilà - keiner gefunden, daher gibt es eine Fehlermeldung über den Befehl nicht gefunden.
In diesem Fall handelt [[
es sich auch nicht um spezielle Metazeichen. Wenn dies der Fall wäre, würde der -e
Teil in [[-e
als Shell-Wort betrachtet, nicht als Argument für [[
sich. Wird [[
jedoch als zusammengesetzter Befehl beschrieben, und das Handbuch sagt Folgendes aus:
Zusammengesetzte Befehle werden mit den folgenden reservierten Wörtern erstellt. Diese Wörter werden nur erkannt, wenn sie nicht in Anführungszeichen stehen und als erstes Wort eines Befehls verwendet werden (dh ihnen können keine Parameterzuweisungen oder Umleitungen vorangestellt werden):
Um [[
als zusammengesetzter Befehl erkannt zu werden, muss es ein erstes Wort eines Befehls oder einer Befehlsliste sein, was nach vorheriger Definition eines "Wortes" impliziert, dass es durch Leerzeichen, Tabulatoren oder Zeilenumbrüche von anderen getrennt werden muss Wörter / Argumente.
Sie haben in den Kommentaren gefragt : "Warum kann der Parser nicht anhalten, sobald er das Muster" [["findet und dies als Beginn eines bedingten Befehls behandelt?" Eine kurze Antwort ist wahrscheinlich, weil 1) der Einfluss der [
Syntax, da es sich ursprünglich um einen externen Befehl handelte, und für POSIX-Standards die Konformität auch heute noch als externer Befehl besteht, und 2) weil der Shell-Parser so aufgebaut ist. Der Shell-Parser kann andere nicht durch Leerzeichen getrennte Sonderzeichen erkennen echo $((2+2))
und (echo foobar)
funktioniert einwandfrei. Vielleicht wird in Zukunft, wenn die ksh
Entwicklung wieder aufgenommen wird oder es einen Fork oder Klon (wie mksh
oder pdksh
) gibt, jemand eine platzlose Syntax implementieren [[-e
.
[[
es als "reserviertes Wort" bezeichnet (siehe Abschnitt 2.9 der Shell-Befehlssprache ). Gemäß der POSIX-Definition muss das reservierte Wort durch Leerzeichen begrenzt werden. Im Gegensatz dazu (
handelt es sich um einen Operator, und die Standardzustände in Abschnitt 2.9 "Die Darstellungen enthalten Abstände zwischen Token an einigen Stellen, an denen <blank>
s nicht erforderlich wäre (wenn einer der Token ein Operator ist)." Siehe verwandte Diskussion: POSIX-Shell-Grammatik: Warum benötigt die Brace-Gruppe den ersten Platz, die Subshell jedoch nicht?char
ist es ein Schlüsselwort, aber Sie können immer noch nicht schreiben charsomeletter = 'A';
und erwarten , dass der Parser nach dem Anzeigen stoppt char
.
i--<=++j
, und der Compiler hat kein Problem damit, das als zu analysieren i -- <= ++ j
.
_
). Ksh hat (
als Operator und (echo hello)
analysiert als ( echo hello )
. Es hat sich if
, {
, [[
und andere Schlüsselwörter , und ifx
, {x
und [[x
jeweils ein Token - wie , wie charsomeletter
ist ein C - Token. Im Gegensatz dazu besteht ein (x
in ksh nicht zitiertes Zeichen aus zwei Token - genau wie i--
zwei Token in C. Was es konzeptionell sogar bedeutet , ein Operator zu sein, unterscheidet sich zwischen Bourne-Shells (wie ksh) und C. Peter A. Schneider wies jedoch auf a hin echte lexikalische Ähnlichkeit.
Es ist wichtig zu beachten, dass [
es sich um einen Befehl handelt und das Shell-Schlüsselwort [[
in bash und ksh auf basiert [
.
[[
wird in ähnlicher Weise verwendet wie [
. Manchmal kann man sogar ersetzen [
]
mit [[
]]
ohne Änderung im Verhalten. Mit [
wie jeder Befehl ist ein Raum zwischen dem Befehl und seine Argumente obligatorisch. Gleiches gilt für [[
.
Früher hatten wir nur /usr/bin/[
. Jetzt haben [
die meisten Shells aus Effizienzgründen eingebaut - aber die Syntax ist dieselbe. In Muscheln, die bieten [[
, fungiert es als vielseitigere Alternative zu [
.
Hier ist die Beschreibung für [
in bash:
$ help [
[: [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.
Ist [
also gleichbedeutend mit test
(abgesehen davon, dass ]
am Ende ein Argument erwartet wird ). help test
wird noch mehr Details dazu geben. Sie können dies mit vergleichen help [[
.
Es gibt auch eine Manpage für den externen Befehl [
( man \[
).
Im Falle des
if [[-e
[
noch [[
ist ein Befehl da. Das ganze Wort [[-e
ist.if [[-e
macht es zu einem Test für wahr / falsch. Existiert also ein Befehl [[-e
? Liegt das daran, dass "[[-" nicht eindeutig ist?
Ja. Oder Nein. [[-e
ist, was es ist: nichts, was die Shell versteht, also nimmt sie an, dass es ihr eigener Befehl ist. ;-);
[[-e
ist ein potenziell gültiger (wenn auch seltsam aussehender) Befehlsname.
Der Raum ist ein Begrenzer und wird benötigt. Wie Sie sehen können aus shellcheck
:
$ shellcheck gmail-browse-msgs-algorithm.sh
In gmail-browse-msgs-algorithm.sh line 847:
[[$Today != "${DaysArr[ i + DAY_DELETED_ON_NDX ]}" ]] && continue
^-- SC1035: You need a space after the [[ and before the ]].
(Sowohl ksh als auch bash unterstützen [[
und funktionieren nicht ohne Leerzeichen. Shellcheck liefert genau diese Ausgabe mit ähnlichen ksh- und bash-Skripten, die diese fehlerhafte Zeile enthalten.)
Warum Deliminatoren benötigt werden, hat mit Token und Lexika zu tun .
ksh
in der Frage nach Shell gefragt hat. Bash leiht [[
Operator von ksh
und in dieser Frage ist ihr Verhalten identisch, aber ich würde vorsichtig mit Annahmen sein, da es einige signifikante Unterschiede zwischen ksh
und bash
Verhalten und Interna gibt. Das liegt nur daran, dass Shellcheck mit Bash-Skripten funktioniert. Es ist möglicherweise nicht unbedingt das geeignete Tool für Ksh-Skripte. Nur etwas zu beachten, wenn Sie sich verschiedenen Muscheln nähern
[[
integrierten Regeln hervorzuheben . Ich habe in keiner Weise gefolgert, dass ksh
es sich um eine Shell handelt, shellcheck
in der Fehler gefunden werden können. Ich hoffe, andere schätzen ksh
und bash
sind zwei verschiedene Interpreten. Danke, dass Sie das erwähnt haben. Erwähnenswert [[
ist auch eine eingebaute Bash, während [
es sich um einen externen Befehl handelt.
[
ist auch eine eingebaute Bash :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html Aber Sie sind nicht weit weg - [
oder test
müssen ein externer Befehl sein. In den Tagen des ursprünglichen Bourne war die Shell [
tatsächlich ein externer Befehl und existiert heute noch, /usr/bin/[
da POSIX einen externen Befehl benötigt. Pubs.opengroup.org/onlinepubs/009695399/utilities/test.html POSIX benötigt nur sehr wenige eingebaut sein pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html Eingebaut [
ist für Effizienz
ksh
; benutze einen Hashbang oder -s ksh
. Übrigens haben ksh und bash [[
"eingebaut", aber es ist ein Schlüsselwort , im Gegensatz zu [
einer eingebauten Shell . (ksh : whence -v [ [[
; bash type [ [[
:) Builtins und externe Befehle sind syntaktisch gleich. Ein Weg, der sich davon [[
unterscheidet, [
besteht darin, dass [[
einige Erweiterungen in seinen Argumenten unterdrückt werden, die als eingebautes Element nicht möglich waren - ebenso wenig wie eine {
Gruppierung, wenn es ein eingebautes Element wäre. Dies kann der Grund sein, warum {x
(oder [[x
) es sich seltsam anfühlt, ein Token zu sein. Ich denke, es ist richtig zu sagen, dass Builtins und Keywords lexikalisch, aber nicht syntaktisch ähnlich sind. @SergiyKolodyazhnyy
[[
kann ein externer Befehl sein! Das heißt, es kann sich um ein Programm handeln und nicht um eine Syntax, die von Ihrer Shell direkt unterstützt wird. Die Unterstützung einer platzlosen Syntax wäre möglich ksh
, würde jedoch auf Systemen mit externem System fehlschlagen. Aus [[
Kompatibilitätsgründen ist es daher besser, den erforderlichen Speicherplatz beizubehalten.
BusyBox stellt [[
beispielsweise einen externen Befehl bereit.
Da [[-e
kann an der Shell-Erweiterung teilnehmen (es kann wie verwendet werden
echo [[-e]*
um alle Dateien beginnend mit einem Buchstaben zwischen aufzulisten [
und e
einschließend), wäre es ein komplettes Chaos, wenn [
und ]
wurden Sonderzeichen nicht in der normalen Leer regierten Wort Spaltung beteiligt.
[[
ist ein Schlüsselwort - vermutlich erfordert der