Mehrzeiliger Befehl mit Kommentaren nach dem Fortsetzungszeichen

29

Erwägen

echo \ # this is a comment
foo

Das gibt:

$ sh foo.sh
 # this is a comment
foo.sh: line 2: foo: command not found

Nach einigen Recherchen im Internet habe ich auf der Schwestersite Stack Overflow eine Lösung von DigitalRoss gefunden . Also kann man machen

echo `: this is a comment` \
foo

oder alternativ

echo $(: this is a comment) \
foo

DigitalRoss erklärte jedoch nicht, warum diese Lösungen funktionieren. Ich würde mich über eine Erklärung freuen. Er antwortete mit einem Kommentar:

Früher gab es einen Shell- gotoBefehl, der zu den :hier angegebenen Bezeichnungen verzweigte . Das gotoist weg, aber Sie können immer noch die : whateverSyntax verwenden ... :ist jetzt eine Art geparster Kommentar.

Aber ich hätte gerne mehr Details und Kontext, einschließlich einer Diskussion über Portabilität.

Wenn jemand andere Lösungen hat, wäre das natürlich auch gut.

Siehe auch die frühere Frage Wie kommentiere ich mehrzeilige Befehle in Shell-Skripten? .


Nachricht zum Mitnehmen aus der folgenden Diskussion. Dies `: this is a comment`ist nur eine Befehlsersetzung. Die Ausgabe von : this is a commentist nichts, und das wird an die Stelle von gesetzt `: this is a comment`.

Eine bessere Wahl ist die folgende:

echo `# this is a comment` \
foo
Faheem Mitha
quelle

Antworten:

25

Kommentare enden in der ersten neuen Zeile (siehe Shell-Token-Erkennungsregel 10 ), ohne Fortsetzungszeilen zuzulassen. Daher befindet sich dieser Code fooin einer separaten Befehlszeile:

echo # this is a comment \
foo

Was Ihren ersten Vorschlag betrifft, folgt auf den umgekehrten Schrägstrich kein Zeilenumbruch, Sie zitieren lediglich das Leerzeichen: Es entspricht

echo ' # this is a comment'
foo

$(: this is a comment)ersetzt die Ausgabe des Befehls : this is a comment. Wenn die Ausgabe dieses Befehls leer ist, ist dies eine sehr verwirrende Möglichkeit, einen Kommentar in die Mitte einer Zeile einzufügen.

Es ist keine Magie im Gange: Es :ist ein gewöhnlicher Befehl, das Doppelpunkt- Dienstprogramm, das nichts tut. Das Doppelpunkt-Dienstprogramm ist vor allem dann nützlich, wenn für die Shell-Syntax ein Befehl erforderlich ist, Sie jedoch zufällig nichts zu tun haben.

# Sample code to compress files that don't look compressed
case "$1" in
  *.gz|*.tgz|*.bz2|*.zip|*.jar|*.od?) :;; # the file is already compressed
  *) bzip2 -9 "$1";;
esac

Ein weiterer Anwendungsfall ist eine Redewendung zum Festlegen einer Variablen, wenn diese noch nicht festgelegt ist.

: "${foo:=default value}"

Die Bemerkung über goto ist historisch. Das Colon-Dienstprogramm stammt noch aus der Zeit vor der Bourne-Shell bis zur Thompson-Shell , die eine goto- Anweisung enthielt . Der Doppelpunkt bedeutete dann eine Bezeichnung; Ein Doppelpunkt ist eine recht gebräuchliche Syntax für goto-Labels (sie ist in sed immer noch vorhanden ).

Gilles 'SO - hör auf böse zu sein'
quelle
OK, ich verstehe. Gibt es eine bessere Möglichkeit, in diesem Zusammenhang Kommentare einzufügen, die Ihnen bekannt sind?
Faheem Mitha
3
@FaheemMitha Wie in dem von Ihnen zitierten Thread empfohlen: Teilen Sie Ihren Befehl in überschaubare Teile auf und kommentieren Sie jeden Teil. Wenn Ihr Befehl so kompliziert ist, dass Sie in der Mitte einen Kommentar benötigen, ist es Zeit, ihn zu vereinfachen!
Gilles 'SO- hör auf böse zu sein'
1
Nun, der fragliche Befehl hat eine Menge Argumente ... Er konvertiert eine Menge Videodateien in eine Datei. Ich sehe keinen direkten Weg, um es zu vereinfachen. Vielleicht eine Liste erstellen und als Argument übergeben? Ich denke, das könnte eine andere Frage sein.
Faheem Mitha
@FaheemMitha Beispiel: make_FINDEin Quickie-Skript, das eine lange Liste von Argumenten für erstellt find. Hier besteht die Motivation für die Erstellung eines Blocks nach dem anderen darin, dass jeder Block aus dem Körper einer Schleife stammt, derselbe Stil es jedoch ermöglicht, jeden Block zu kommentieren.
Gilles 'SO- hör auf böse zu sein'
1
Danke für das Beispiel. Mein Beispiel ist im Grunde genommen nur eine lange Liste von Namen, die einem Befehl als Argumente gegeben werden. Ich möchte Kommentare zu jedem Namen, da dies für mich der einfachste Weg ist, den Kontext zu bewahren. Ich sehe keinen offensichtlichen Weg, um den Befehl in Teile zu zerlegen, und wenn ich das täte, könnte es ihn noch länger machen, und es ist schon lang genug.
Faheem Mitha
6

Sie können dies mit Bash-Arrays erreichen, z

#!/bin/bash
CMD=(
  echo  # this is a comment
  foo
  )

"${CMD[@]}"

Dies definiert ein Array $CMDund erweitert es dann. Nach dem Erweitern wird die resultierende Zeile ausgewertet und in diesem Fall echo fooausgeführt.

Der Text zwischen (und )definiert das Array und unterliegt der üblichen Bash-Syntax, sodass alle Zeilen danach #ignoriert werden.

Hinweis zum Beibehalten von Leerzeichen in Anführungszeichen

${CMD[@]}Wird zu einer einzelnen Zeichenfolge erweitert, die die Verkettung aller Elemente darstellt, die durch ein Leerzeichen getrennt sind. Einmal erweitert, parst Bash den String dann wie gewohnt in Token (vgl. $ IFS ), was oft nicht das ist, was wir wollen.

Im Gegensatz dazu bleibt "${CMD[@]}"jedes Element im Array erhalten, wenn die Erweiterung in doppelte Anführungszeichen eingeschlossen wird. Betrachten Sie den Unterschied zwischen hello world second itemund "hello world" "second item".

Bildhaftes Beispiel:

# LIST=("hello world" "second item")

# for ITEM in ${LIST[@]}; do echo $ITEM; done
hello
world
second
item

# for ITEM in "${LIST[@]}"; do echo $ITEM; done
hello world
second item
RobM
quelle
Vielen Dank für die Antwort, @RobM. Ihr Vorschlag ist es also, die Kommentare / Metainformationen zu den Elementen in der Liste in das Bash-Array selbst aufzunehmen? Diese Frage wäre wahrscheinlich nützlicher, wenn ich ein Beispiel für die Art von Befehl aufgenommen hätte, die ich verwenden wollte. Ich weiß nicht, warum ich es nicht getan habe.
Faheem Mitha
Es stellte sich heraus, dass ich Ihre Frage nicht sorgfältig gelesen hatte. Ich dachte, du stellst die Frage, mit der du verbunden bist. Hoppla. :)
RobM
${CMD[@]}wird nicht zu einer einzelnen Zeichenfolge erweitert. - Es wird auf viele Zeichenfolgen erweitert: Nicht nur für jedes Element des Arrays, sondern auch für jedes Leerzeichen in jedem Element. (Dh: völlig nutzlos)
Robert Siemer
4

Sie nicht tun $(: comment). Das ist kein Kommentar - das ist eine Subshell - ein weiterer ganz neuer Shell-Prozess für die meisten Shells. Ihr Ziel ist es , weniger mit Ihrer Eingabe zu tun , nicht mehr, und das ist, was das tun würde - auch wenn es sinnlos ist.

Sie können stattdessen tun ...

printf '<%s>\n' some args here ${-##*"${--

                my long comment block

                }"}  and "more ${-##*"${--

                and another one in the
                middle of the quoted string
                there shouldn\'t b\e any special &
                (character) `echo issues here i hope >&2`
                basically anything that isn\'t a close \}
                $(echo the shell is looking for one >&2)
                }$(echo "}'"\" need backslash escaping >&2
                                )${-##*${--

                nesting is cool though

             }}"}here too"

}'" need backslash escaping
<some>
<args>
<here>
<and>
<more here too>

Grundsätzlich passiert dort, dass die Shell eine Substitution durchführt. Es ersetzt den Wert des speziellen Shell-Parameters $-jedes Mal zweimal. Es ist ohnehin eine kurze Zeichenfolge, aber sie ist immer gesetzt - und daher wird die innere Ersetzung, die als Muster interpretiert wird, das von der äußeren entfernt wird, nicht auf den Inhalt zwischen den Klammern ausgedehnt, wenn ich das -Erweiterungsformular verwende.

Hier:

bash -x <<""
printf %s\\n '${-##*"'${-- a set param doesn\'t expand to this optional text }'"}'

+ printf '%s\n' '${-##*"hxB"}'
${-##*"hxB"}

Sehen? Es ist also nur zweimal erweitert. Sobald die Shell feststellt, dass der Parameter gesetzt ist, wird fast alles im optionalen Erweiterungsfeld verworfen und es wird zu seinem gesamten Wert erweitert, der von sich selbst entfernt wird, und so zu gar nichts. In den meisten Shells müssen Sie nicht einmal Anführungszeichen entkommen, sondern es ist basherforderlich.

Besser noch ist:

COMMENT=
echo      ${COMMENT-"
           this will work the same way
           but the stripping isn\'t
           necessary because, while
           the variable is set, it is also
           empty, and so it will expand to
           its value - which is nothing
           "} this you\'ll see

this you'll see
mikeserv
quelle