Verstehen Sie die komplexe Befehlsersetzung mit {} und mehreren `\ls`

Verstehen Sie die komplexe Befehlsersetzung mit {} und mehreren `\ls`

Ich versuche, diese Zeile aus einem Shell-Skript zu verstehen. Ich weiß, dass das $(..)bedeutet, dass Sie das ausführen ..und seine Ausgabe dort einfügen, wo Sie $()in einer Anweisung suchen. Aber was passiert zwischen diesen Klammern? Was macht das \lsund wie verhält sich das zu dem \in den vorherigen Zeilen? Ist das eine \\Aufteilung auf zwei Zeilen? Ist \lsdas dasselbe wie das normale ls?

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

Antwort1

Die Ausgabe der drei lsBefehle wird an den Befehl weitergeleitet paste, der sie zum folgenden Wert zusammenführt:

$VOLTDB_VOLTDB"/voltdb-*.jar:$VOLTDB_LIB"/*.jar:$VOLTDB_LIB"/extension/*.jar

NOTIZ:Die Variablen $VOLTDB_VOLTDBund $VOLTDB_LIBwerden erweitert und es kann mehr Werte als nur eine Datei für jeden dieser lsBefehle geben. Sehen Sie das *dort? Das ist ein Glob-Zeichen, das als Platzhalter fungiert und beispielsweise auf alles zwischen der linken Seite (voltdb-) und der rechten Seite (.jar) erweitert wird.

Diese würden passen:

voltdb-1.jar
voltdb-blah.jar
voltdb-12345.jar

Alles wird dann in die Variable aufgenommen APPCLASSPATH:

APPCLASSPATH=$CLASSPATH:$VOLTDB_VOLTDB"/voltdb....etc.

Der Befehl „Einfügen“

Hier ist ein Beispiel, in dem ich den Befehl verwende, sequm eine Zahlenfolge von 1-10 zu generieren.

$ seq 10 | paste -sd ':' -
1:2:3:4:5:6:7:8:9:10

Sie können sehen, dass der pasteBefehl die Ausgabe zusammenführt und mit einem Doppelpunkt ( :) trennt.

Sie können den Beispielbefehl auch folgendermaßen nachahmen:

$ { echo "hi1"; echo "hi2"; echo "hi3"; } | paste -sd ':' -
hi1:hi2:hi3

NOTIZ:Der -Befehl „to the paste“ weist ihn an, die Eingabe von STDIN zu übernehmen und jedes Argument so auszudrucken, wie es eingeht, getrennt durch ein :.

Mit verschiedenen Schaltern pastelässt sich zudem eine Aufteilung der Daten in Gruppen erreichen, basierend auf der Anzahl der -dahinter stehenden 's.

Beispiele einfügen

Hier ist ein Beispiel mit 2 -.

$ seq 10 | paste - -
1       2
3       4
5       6
7       8
9       10

Hier sind 3 -.

$ seq 10 | paste - - -
1       2       3
4       5       6
7       8       9
10

Es gibt also an, pastewie viele Argumente pastein jeder Zeile gedruckt werden sollen. Aber lassen Sie sich nicht verwirren, das Beispiel, mit dem Sie arbeiten, nimmt einfach die Eingabe von STDIN, trennt jedes Argument durch Leerzeichen und druckt es, gefolgt von einem :. Wenn Sie mehrere -'s angeben, geben Sie an, pastedass Argumente übernommen werden sollen, 2 auf einmal, 3 auf einmal usw.

Immer zwei Argumente gleichzeitig, getrennt durch :'s:

$ seq 10 | paste -d ':' - -
1:2
3:4
5:6
7:8
9:10

$ seq 10 | paste -d ':' - - -
1:2:3
4:5:6
7:8:9
10::

Wenn Sie übrigens den -sSchalter einschließen, weisen Sie ihn an, pastedie Argumente seriell (nacheinander) zu übernehmen. Beobachten Sie, was passiert, wenn Sie ihn in einem der obigen Beispiele verwenden.

2 auf einmal:

$ seq 10 | paste -sd ':' - -
1:2:3:4:5:6:7:8:9:10

3 auf einmal:

$ seq 10 | paste -sd ':' - - -
1:2:3:4:5:6:7:8:9:10

Antwort2

$(command)führt einen Befehl aus und ersetzt seine Ausgabe.

{ list; }ist ein Gruppenbefehl, der mehrere Befehle in der aktuellen Shell-Umgebung ausführt. Er ist ähnlich wie (list), erstellt aber keine Subshell.

\commandwird verwendet, um Aliase zu Befehlen zu ignorieren, die das erwartete Verhalten eines Befehls erheblich verändern können.

Das \am Ende der Zeile bedeutet lediglich, dass diese Zeile fortgesetzt wird, sodass die Shell die nächste Zeile als Teil der aktuellen betrachtet. Normalerweise nicht erforderlich, wenn dies aus dem Kontext (öffnende Klammer oder Anführungszeichen) offensichtlich ist.

Antwort3

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

\lsist wie ls, außer dass lsder Backslash die Aliaserweiterung verhindert, wenn es sich um einen Alias ​​handelt. Dies garantiert, dass der lsBefehl verwendet wird und nicht irgendein Alias, der möglicherweise unerwünschte Ausgaben wie ein Klassifizierersuffix ( -F) hinzufügt.

Die lsBefehle, die mit vorhandenen Dateinamen als Argumente aufgerufen werden, listen ihre Argumente auf, eines pro Zeile. Die Option -1hat keine Wirkung, da die Ausgabe von lsan eine Pipe und nicht an ein Terminal geht. Wenn lsein Argument empfangen wird, das nicht der Name einer vorhandenen Datei ist, wird in der Standardausgabe nichts angezeigt, sondern stattdessen ein Fehler. Fehler von den lsBefehlen werden von nirgendwohin umgeleitet 2> /dev/null. Es gibt zwei Gründe, warum lsmöglicherweise ein Argument empfangen wird, das keine Datei ist: wenn eine der Variablen nicht auf ein vorhandenes, lesbares Verzeichnis verweist oder wenn keine Datei vorhanden ist, die dem Platzhaltermuster entspricht. In beiden Fällen wird das Muster unerweitert an übergeben ls.

Die Backslashes am Ende der Zeilen bewirken, dass die Shell den folgenden Zeilenumbruch ignoriert. Keiner von ihnen ist hier sinnvoll, da die Shell an jeder Stelle, an der sie verwendet werden, einen optionalen Zeilenumbruch erwartet.

Die Klammern { … } gruppieren die Befehle. Der zusammengesetzte Befehl { \ls …; \ls …; \ls … ; }wird weitergeleitet pasteund seine Fehler werden an umgeleitet /dev/null.

Der pasteBefehl verbindet alle Eingabezeilen mit einem :dazwischen. Dies ist äquivalent zu , außer dass am Ende tr '\n' :kein ein eingefügt wird .:

Durch die Befehlsersetzung $(…)wird die Ausgabe von pastein interpoliert APPCLASSPATH, wobei nach dem Wert der CLASSPATHVariablen ein Doppelpunkt die beiden Teile trennt.

Hier ist eine vereinfachte Version. Diese unterscheidet sich geringfügig vom Original, da, wenn keines der Platzhaltermuster mit etwas übereinstimmt, „ gleich “ ohne zusätzlichen abschließenden Doppelpunkt APPCLASSPATHist (was wahrscheinlich wünschenswert ist).CLASSPATH

APPCLASSPATH=$CLASSPATH:$(
  \ls "$VOLTDB_VOLTDB"/voltdb-*.jar "$VOLTDB_LIB"/*.jar "$VOLTDB_LIB"/extension/*.jar |
  tr '\n' :) 2>/dev/null
APPCLASSPATH=${APPCLASSPATH%:}

verwandte Informationen