Was ist der Unterschied zwischen Echo "Datum", Echo "Datum" und Echo "Datum"?

22

Was ist der Unterschied zwischen diesen drei Befehlen?

echo `date`
echo "`date`"
echo '`date`'

Ich bin verwirrt über die tatsächlichen Unterschiede. Ich denke, wenn die 'um es bedeutet, dass es eine Zeichenfolge ist, würde Echo daher buchstäblich die Zeichenfolge ausgeben, dateanstatt das Datum anzuzeigen?

John
quelle

Antworten:

19

`date` wird nur auf die Ausgabe des dateBefehls erweitert. Es werden jedoch zusätzliche Leerzeichen an Stellen entfernt, an denen die Ausgabe mehr als ein aufeinanderfolgendes Leerzeichen enthält. (Dies liegt daran, dass die Befehlsersetzung einer Wortteilung unterliegt und der echoBefehl mehrere Argumente verarbeitet.)

In "` date` " sind die doppelten Anführungszeichen schwache Anführungszeichen, sodass sie Variablen erweitern (versuchen Sie" $ PWD ") und eine Befehlssubstitution durchführen. Das Ergebnis der Erweiterung wird als einzelnes Argument an den echoBefehl übergeben, wobei alle aufeinander folgenden Leerzeichen enthalten sind. Das heißt, die Wortteilung wird nicht durchgeführt.

In "Datum" sind die einfachen Anführungszeichen stärkere Anführungszeichen, sodass sie keine Erweiterung der Variablen oder keine Befehlsersetzung in ihnen ermöglichen.

Weitere Erklärungen finden Sie unter diesem Link .

Bearbeitet den ersten Punkt, wie von Michael Suelmann im Kommentar unten richtig gezeigt .

Chirag Bhatia - chirag64
quelle
1
Wie genau heißt das Zeichen, das das Datum umgibt? Wenn ich richtig verstehe, funktionieren Metazeichen nicht in einfachen Anführungszeichen?
John
Wenn ich richtig verstehe, funktionieren Metazeichen nicht in einfachen Anführungszeichen?
John
8
Das `wird in diesem Szenario und in verschiedenen Unix-Dokumentationen / Büchern oft als" Backtick "bezeichnet. Es wird nicht wirklich als Unicode-Akzent verwendet, wenn es für sich genommen so ist, obwohl das der Name des Symbols ist. Und Sie haben Recht, dass keine Erweiterung von Metazeichen / Ausdrücken auftritt, wenn Sie diese in einfache Anführungszeichen setzen.
Jim Stewart
Ihre erste Aussage ist falsch, da die Ausgabe je nach Datum oder Gebietsschema leicht abweichen kann. Nur der zweite Befehl gibt das Gleiche aus wie der bloße dateBefehl.
Juli
1
@BonsiScott Das zusätzliche Leerzeichen zwischen "Nov" und "1" wird auch in HTML entfernt;)
Izkata
16

Beide

echo `date`

und

echo "`date`"

zeigt das Datum an. Die Ausgabe von letzterem sieht aus wie die Ausgabe datevon sich selbst ausgeführt.

Es gibt jedoch einen Unterschied: Der in "Anführungszeichen eingeschlossene "wird echoals einzelnes Argument an gesendet . Die Anführungszeichen kapseln die Ausgabe des gesamten Befehls als ein Argument. Da echonur die Argumente der Reihe nach mit Leerzeichen dazwischen ausgedruckt werden, sieht es im Grunde gleich aus.

Hier ist ein Beispiel für den subtilen Unterschied:

echo `date`

produziert:

Fri Nov 1 01:48:45 EST 2013

aber:

echo "`date`"

produziert:

Fri Nov  1 01:48:49 EST 2013

Beachten Sie, dass die beiden nachfolgenden Leerzeichen Novohne Anführungszeichen auf eins reduziert wurden. Dies liegt daran, dass die Shell jedes durch Leerzeichen getrennte Element analysiert und das Ergebnis als 6 Argumente an echo sendet. Wenn Sie es zitieren, erhält echo ein einziges Argument und die Anführungszeichen behalten den Raum bei.

Dies wird bei Befehlen, die kein Echo sind, viel wichtiger. Stellen Sie sich zum Beispiel einen Befehl vor foo, der zwei Argumente benötigt: ein Datum und eine E-Mail-Adresse.

Dies funktioniert in diesem Szenario:

foo "`date`" joeuser@example.com

Dies wird das Skript jedoch verwirren, indem 7 Argumente gesendet werden:

foo `date` joeuser@example.com
Jim Stewart
quelle
3
Sie widersprechen sich in Ihrem ersten Satz. Das erste und zweite Formular geben nicht immer dasselbe aus, wie Sie später demonstrieren.
Juli
Vielen Dank. Ich habe den Wortlaut geändert, um ihn klarer zu machen.
Jim Stewart
3

In POSIX-Shells `date`ist dies die alte Form der Befehlsersetzung. Die moderne Syntax ist $(date).

In beiden Fällen werden sie auf die Ausgabe von erweitert, datewobei die nachfolgenden Zeilenumbrüche entfernt werden (vorausgesetzt, die Ausgabe enthält keine NUL-Zeichen).

Wenn sich echodiese Erweiterung jedoch nicht in doppelten Anführungszeichen und in Listenkontexten befindet (z. B. in Argumenten für einfache Befehle wie in Ihrem Fall), unterliegt sie den folgenden Bedingungen:

  1. Wort Splitting : dass das ist „Ausgabe des datemit dem hinteren Zeilenenden gestrippt“ wird aufgeteilt entsprechend den aktuellen Wert der $IFSVariablen (standardmäßig enthaltenden Raum, Tab und Neue - Zeile (und NUL mit zsh)) in mehrere Worte .

    Zum Beispiel, wenn dateAusgänge Fri 1 Nov 14:11:15 GMT 2013\n(wie es oft in einem englischen Gebietsschema und in einem Festland britische Zeitzone), und $IFSenthalten derzeit :, das werden aufgeteilt in 3 seine Worte : Fri 1 Nov 14, 11und 15 GMT 2013.

  2. Dateiname Generation (aka Globbing ) (außer bei zsh): Das heißt, jedes Wort aus der Aufspaltung oben ergibt , wird für Wildcard - Zeichen sieht ( *, ?, [...]obwohl einige Granaten mehr haben), und in der Liste der Dateinamen erweitert , dass diese Muster entsprechen. Zum Beispiel, wenn der Ausgang dateist ?%? 33 */*/* UVC 3432(wie es oft in Venusian Gegenden und UVC Zeitzone), und $IFSist der Standardwert), dann ist das sich ausdehnt , um alle nicht verborgen 3 Zeichen Dateinamen im aktuellen Verzeichnis , dessen mittlere Charakter ist %, 33, alle alle nicht versteckten Dateien in den nicht versteckt Verzeichnisse aller nicht verborgenen Verzeichnisse des aktuellen Verzeichnisses, UVCund 3432.

Deswegen:

  1. Sie sollten Befehlsersetzungen immer in Anführungszeichen setzen (mit doppelten Anführungszeichen), es sei denn, Sie möchten, dass die Wortteilung oder die Dateinamenerzeugung bei ihrer Erweiterung durchgeführt wird
  2. Wenn Sie das Wort teilen möchten , sollten Sie $IFSdie Zeichen auswählen, die Sie teilen möchten.
  3. Wenn Sie eine Wortteilung, aber keine Dateinamenerzeugung wünschen , müssen Sie ein ausgeben set +f, um sie zu deaktivieren.

Die einzelnen Anführungszeichen geben alles an, sodass die Backtick-Zeichen wörtlich genommen werden.

Beispiel (mit -xwird es einfacher zu sehen, was los ist):

$ bash --norc -x
bash-4.2$ IFS=:
+ IFS=:
bash-4.2$ echo `date`
++ date
+ echo 'Fri  1 Nov 14' 42 '33 GMT 2013'
Fri  1 Nov 14 42 33 GMT 2013
bash-4.2$ echo "`date`"
++ date
+ echo 'Fri  1 Nov 14:42:41 GMT 2013'
Fri  1 Nov 14:42:41 GMT 2013

bash-4.2$ cd /lib/modules
+ cd /lib/modules
bash-4.2$ export TZ=UVC LC_ALL=vs_VS
+ export TZ=UVC LC_ALL=vs_VS
+ TZ=UVC
+ LC_ALL=vs_VS
bash-4.2$ unset -v IFS     # get the default behaviour
+ unset -v IFS
bash-4.2$ echo `date`
++ date
+ echo '?%?' 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
?%? 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
bash-4.2$ echo "`date`"
++ date
+ echo '?%? 33 */*/* UVC 3432'
?%? 33 */*/* UVC 3432

Wenn die Ausgabe NUL-Zeichen enthält, ist das Verhalten von Shell zu Shell unterschiedlich: Einige entfernen sie, andere kürzen die Ausgabe beim ersten NUL-Zeichen, zshbehalten sie bei, beachten Sie jedoch, dass externe Befehle keine Argumente akzeptieren können, die NULs enthalten

Stéphane Chazelas
quelle
Eine eigentliche "POSIX-Shell" gibt es nicht. Es gibt Shells, die mit einer begrenzten Teilmenge ihrer Funktionalität den verschiedenen relevanten POSIX-Standards entsprechen können.
fpmurphy
0

Mit `date` erhalten Sie die Ausgabe des Datums in mehrere Wörter aufgeteilt, da die Wortteilung nach der Befehlsersetzung erfolgt.

Mit "` date` "erhalten Sie die Ausgabe des Datums als ein Wort / Parameter, da zwischen doppelten Anführungszeichen eine Befehlsersetzung erfolgt, die Ausgabe jedoch nicht weiter analysiert wird. Dasselbe gilt für Variablenerweiterungen wie "$ i" in meinem Beispiel unten.

Mit "Datum" erhalten Sie ein buchstäbliches "Datum", da keine Befehlsersetzung zwischen einfachen Anführungszeichen erfolgt.

Vielleicht werden die Unterschiede der 3 Formen auf diese Weise deutlicher:

> for i in `date`; do echo "$i"; done
Fr
1.
Nov
12:25:30
CET
2013

> for i in "`date`"; do echo "$i"; done
Fr 1. Nov 12:25:38 CET 2013

> for i in '`date`'; do echo "$i"; done
`date`
Michael Suelmann
quelle