Was bedeuten die Paranthesis und das $ -Zeichen in echo $ (ls)

8

Die Ausgabe von

# ls

und

# echo $(ls)

sind gleich. Was genau bedeuten das $ -Zeichen und die Klammer?

Was passiert auf technischer Ebene, wenn die Ausgabe dieser beiden Befehle gleich ist?

user784637
quelle

Antworten:

6

Dies ist die Befehlsersetzung für bash.

Durch die Befehlsersetzung kann die Ausgabe eines Befehls den Befehl selbst ersetzen. Die Befehlsersetzung erfolgt, wenn ein Befehl wie folgt eingeschlossen ist:

 $(command) or

 `command`

http://www.gnu.org/software/bash/manual/bashref.html#Command-Substitution

Mehr:

http://tldp.org/LDP/abs/html/commandsub.html

http://wiki.bash-hackers.org/syntax/expansion/cmdsubst

Und ein gutes Beispiel ähnlich Ihrer Frage:

http://bashshell.net/shell-scripts/using-command-substitution-in-a-bash-shell-script/

herzmagisch
quelle
3

Wenn die Shell auf eingeschlossenen Text stößt $( ), gilt Folgendes:

  1. Nimmt es als Befehl und führt den Befehl (wie Panther sagt ) in einer Subshell aus .
  2. Ersetzt die Ausgabe des Befehls anstelle des gesamten Ausdrucks. Alle nachfolgenden Zeilenumbrüche werden aus dieser Ausgabe entfernt.$(...)
  3. Führt weitere Expansionen , wenn nicht angegeben (siehe unten).$(...)

Wie die Antwort von heartmagic erklärt, ist dies eine von zwei verfügbaren Syntaxen für die Befehlssubstitution .

"Was ... bewirkt, dass die Ausgabe dieser beiden Befehle gleich ist?"

Es ist eigentlich etwas ungewöhnlich , dass der Ausgang lssein genau das gleiche wie die Ausgabe von echo $(ls):

ek@Io:~/tmp$ ls
bar  foo
ek@Io:~/tmp$ echo $(ls)
bar foo

lsTrennt Dateinamen normalerweise durch zwei oder mehr Leerzeichen oder eine neue Zeile. Dies hilft uns, sie leichter voneinander zu unterscheiden, insbesondere da Leerzeichen in Dateinamen etwas häufig vorkommen (aber mehrere aufeinanderfolgende Leerzeichen, weniger häufig).

Wortteilung

Als ich rannte echo $(ls), passierte Folgendes.

  1. Befehlsersetzung ersetzt$(ls)durch:

    bar
    foo

    Sie werden überrascht sein, das zu hören, da Sie das wahrscheinlich nicht sehen, wenn Sie lsalleine laufen ! Diese Ungleichheit bei den lsAusgaben wird im Folgenden erläutert, ist jedoch nicht der Grund, warum zwischen diesen beiden Wörtern nur ein Leerzeichen steht. Dasselbe würde passieren, wenn $(ls)es durch bar foo(mit zwei Leerzeichen) ersetzt würde.

  2. Anschließend führte die Shell eine Wortaufteilung durch , wobei der Befehl als separate Argumente behandelt wurde barund nicht fooals einzelnes Argument, das Leerzeichen enthielt.echo

    Globbing (aka Dateiname / Pfadnamenerweiterung) würde auch durchgeführt werden, wenn die Ausgabe des Befehls enthalten hatte *, ?oder [.

    Wie unten ausgeführt, ermöglicht das Zitieren mit doppelten Anführungszeichen das Ersetzen von Befehlen, unterdrückt jedoch das Aufteilen und Globbing von Wörtern.

Wenn echomehrere Argumente empfangen werden (mit Ausnahme von Optionen wie -n, die speziell behandelt und überhaupt nicht gedruckt werden), werden sie alle mit einem einzigen Leerzeichen zwischen den nachfolgenden Argumenten ausgedruckt. echodruckt dann eine neue Zeile, sofern die -nOption nicht übergeben wurde.

So echo $(ls)zeigt Ausgabe wie bar foostatt bar foo.

Wenn Sie laufen lsund listet keine Dateien oder nur eine Datei, die Ausgabe des lsWillens oft die gleiche sein wie die Ausgabe von echo $(ls). Selbst dann ist es nicht immer dasselbe, z. B. wenn ein Dateiname andere Leerzeichen als isolierte (einzelne) Leerzeichen enthält:

ek@Io:~/tmp2$ touch 'my   file'
ek@Io:~/tmp2$ ls
my   file
ek@Io:~/tmp2$ echo $(ls)
my file

Wenn lsmehrere Dateien gedruckt werden, entspricht die Ausgabe wahrscheinlich nicht genau der Ausgabe von $(ls). Ähnlich:

  • echo a bund echo $(echo a b)produzieren die gleiche Ausgabe, aber
  • echo 'a b'und echo $(echo 'a b')nicht.

Dies ist eine wichtige Sache, die Sie über die Befehlssubstitution wissen sollten. Nicht zitierte Befehlssubstitutionen unterliegen der Wortaufteilung (und dem Globbing) .

Zitieren

Wenn Sie verhindern möchten , dass einzelne Wörter aufgespalten und Globbing --und Sie in der Regel werden sie verhindern wollen - Sie Ihren Ausdruck für Kommandosubstitution in beilegen können doppelte Anführungszeichen ( " "). Der Grund für die Verwendung von doppelten Anführungszeichen anstelle von einfachen Anführungszeichen ist, dass einfache Anführungszeichen noch stärker sind. Sie würden die Befehlsersetzung unterdrücken.

Dies gilt auch für die Parametererweiterung , die eine häufiger verwendete Shell-Erweiterung als die Befehlssubstitution ist, und für die arithmetische Erweiterung . Die Gründe, warum es wichtig ist, Befehlsersetzungen anzugeben (außer in dem eher ungewöhnlichen Fall), dass Sie wissen , dass weitere Erweiterungen auftreten sollen, sind dieselben wie die Gründe für die Angabe der Parametererweiterung .

Terminalerkennung

Doppelte Anführungszeichen reichen oft aus, um unerwartete Ergebnisse bei der Befehlssubstitution zu vermeiden. Insbesondere funktioniert es mit den echoobigen Beispielen sowie dem Beispiel lseines Verzeichnisses mit einem einzelnen Eintrag, der Leerzeichen enthält:

ek@Io:~/tmp2$ echo "$(ls)"
my   file

Jedoch, wie oben erwähnt, könnten Sie überrascht feststellen , dass das, was Sie sehen , wenn Sie laufen lsoft nicht der Fall ist , was übergeben wird echovon an Ort und Stelle "$(ls)":

ek@Io:~/tmp$ ls
bar  foo
ek@Io:~/tmp$ echo "$(ls)"
bar
foo

Dies liegt daran, dass lsüberprüft wird, ob die Standardausgabe ein Terminal ist , um zu entscheiden, wie die Ausgabe formatiert werden soll, wenn die Ausgabeformatierung nicht explizit angegeben ist.

  • Wenn stdout ein Terminal ist, werden lsAusgaben in vertikal sortierten Spalten wie z ls -C.
  • Wenn stdout kein Terminal ist, lslistet jeder Eintrag in einer eigenen Zeile auf, wie z ls -1.

Bei der Befehlssubstitution ist die Standardausgabe kein Terminal, da die Ausgabe des Befehls nicht direkt an ein Terminal gesendet wird, damit Sie sie sehen können. Stattdessen wird sie von der Shell erfasst und als Teil eines anderen Befehls verwendet.

lsÜbergeben Sie das -CFlag , um eine mehrspaltige Formatierung beim Ausführen über die Befehlsersetzung zu erhalten :

ek@Io:~/tmp$ echo "$(ls -C)"
bar  foo

( dirwird manchmal als Alternative dazu vorgeschlagen ls -Cund funktioniert auch dafür, dirverhält sich aber ls -C -beher wie als nurls -C .)

Shell-Aliasing

Ein weiterer Grund lskann manchmal verhalten sich anders als echo "$(ls)"ist , dass lssein kann ein Shell - Alias . Führen Sie aus alias ls, um zu überprüfen; unter Ubuntu bekommt man normalerweise alias ls='ls --color=auto'. Dies macht es so, dass, wenn es lsals erstes Wort eines Befehls angezeigt wird, den Sie interaktiv ausführen (und auch in der weitaus selteneren Situation, dass die Alias-Erweiterung in einer nicht interaktiven Shell aktiviert wurde), es durch ersetzt wird ls --color=auto.

Wenn ich zum Beispiel laufe ls, werden Verzeichnisse aufgelistet, die blau und grün gefärbt sind (und es werden auch viele andere Farbregeln beachtet). --color=autobewirkt ls, dass eine farbige Ausgabe gedruckt wird, wenn die Standardausgabe ein Terminal ist, und nicht anders.

Übergeben Sie die Option oder, um eine farbige Ausgabe beim Ausführen lsüber die Befehlsersetzung zu erhalten . Wenn Sie möchten, können Sie dies kombinieren mit :--color--color=always-C

echo $(ls -C --color)

Beachten Sie, dass Sie zwar lseinen Alias ​​für ls --coloroder ls --color=alwaysanstelle von erstellen ls --color=autokönnen und ls --color=alwayses egal ist, ob die Standardausgabe ein Terminal ist ... dieser Alias ​​jedoch immer noch keine lsfarbige Ausgabe erzeugt, wenn er durch Befehlsersetzung aufgerufen wird. Dies liegt daran, dass Shell-Aliase (in Bourne-Shells wie bash ) nur erweitert werden, wenn die Shell sie als erstes Wort eines Befehls sieht und sie nicht von Subshells geerbt werden.

Eliah Kagan
quelle
-1

Wenn Sie $ vor einem Variablennamen verwenden, wird der der Variablen zugewiesene Wert aufgerufen. Echo ohne $ gibt nur den Namen der Variablen auf dem Bildschirm aus (oder Standardausgabe).

Haziz
quelle
1
(ls)ist kein Variablenname.
Eliah Kagan