Kommentieren in einem Bash-Skript innerhalb eines mehrzeiligen Befehls

164

Wie kann ich jede Zeile der folgenden Zeilen eines Skripts kommentieren?

cat ${MYSQLDUMP} | \
sed '1d' | \
tr ",;" "\n" | \
sed -e 's/[asbi]:[0-9]*[:]*//g' -e '/^[{}]/d' -e 's/""//g' -e '/^"{/d' | \
sed -n -e '/^"/p' -e '/^print_value$/,/^option_id$/p' | \
sed -e '/^option_id/d' -e '/^print_value/d' -e 's/^"\(.*\)"$/\1/' | \
tr "\n" "," | \
sed -e 's/,\([0-9]*-[0-9]*-[0-9]*\)/\n\1/g' -e 's/,$//' | \
sed -e 's/^/"/g' -e 's/$/"/g' -e 's/,/","/g' >> ${CSV}

Wenn ich versuche, einen Kommentar hinzuzufügen wie:

cat ${MYSQLDUMP} | \ # Output MYSQLDUMP File

Ich bekomme:

#: not found

Kann man hier einen Kommentar abgeben?

BassKozz
quelle
1
Nun, wie Sie bemerkt haben, wird das \, wenn Sie zuerst # tun, nur ein Teil des Kommentars, aber wenn Sie \ zuerst tun, ändern die späteren Zeichen in der Zeile ihre Bedeutung weg von "Zeilenfortsetzung" in "Zitat". Ich habe an eine Lösung gedacht, die unten angegeben ist.
DigitalRoss
1
Mögliches Duplikat von Wie man einen Linienkommentar für einen
mehrzeiligen

Antworten:

203

Dies hat einige Gemeinkosten, aber technisch beantwortet es Ihre Frage:

echo abc `#Put your comment here` \
     def `#Another chance for a comment` \
     xyz, etc.

Und speziell für Pipelines gibt es eine saubere Lösung ohne Overhead:

echo abc |        # Normal comment OK here
     tr a-z A-Z | # Another normal comment OK here
     sort |       # The pipelines are automatically continued
     uniq         # Final comment

Siehe Frage zum Stapelüberlauf So setzen Sie einen Zeilenkommentar für einen mehrzeiligen Befehl .

DigitalRoss
quelle
1
Scheint ziemlich komplex, wenn es keine einfachere Methode gibt?
BassKozz
1
Ok, ich habe eine etwas einfachere Variante hinzugefügt.
DigitalRoss
1
Können Sie Ihre Antwort ändern, um zu zeigen, dass der Backslash nicht benötigt wird, damit ich die Kommentare neben jede Zeile setzen und einfach eine Pipe verwenden kann?
BassKozz
Ich habe überprüft, ob die Versionen eins und zwei funktionieren. Können Sie jedoch erklären, warum sie dies tun und was hier vor sich geht? Vielen Dank.
Faheem Mitha
1
Danke für die Erklärung. Ich habe eine Frage auf unix.sx geöffnet und nach weiteren Details gefragt. Bash mehrzeiliger Befehl mit Kommentaren nach dem Fortsetzungszeichen .
Faheem Mitha
39

Der nachfolgende Backslash muss das letzte Zeichen in der Zeile sein, damit er als Fortsetzungsbefehl interpretiert werden kann. Danach sind keine Kommentare oder Leerzeichen mehr zulässig.

Sie sollten in der Lage sein, Kommentarzeilen zwischen Ihre Befehle zu setzen

# output MYSQLDUMP file
cat ${MYSQLDUMP} | \
# simplify the line
sed '/created_at/d' | \
# create some newlines
tr ",;" "\n" | \
# use some sed magic
sed -e 's/[asbi]:[0-9]*[:]*//g' -e '/^[{}]/d' -e 's/""//g' -e '/^"{/d' | \
# more magic
sed -n -e '/^"/p' -e '/^print_value$/,/^option_id$/p' | \
# even more magic
sed -e '/^option_id/d' -e '/^print_value/d' -e 's/^"\(.*\)"$/\1/' | \
tr "\n" "," | \
# I hate phone numbers in my output
sed -e 's/,\([0-9]*-[0-9]*-[0-9]*\)/\n\1/g' -e 's/,$//' | \ 
# one more sed call and then send it to the CSV file
sed -e 's/^/"/g' -e 's/$/"/g' -e 's/,/","/g' >> ${CSV}
Mob
quelle
12
Das \ ist nicht erforderlich, wenn die Pipeline-Befehlskomponente mit | endet
DigitalRoss
2
DigitalRoss, Sie haben Recht, ich kann nur die Pipe und nicht den Backslash verwenden und dann funktionieren meine # Kommentare perfekt ... können Sie das als Antwort posten, damit ich es akzeptieren kann.
BassKozz
8
"Sie sollten in der Lage sein, Kommentarzeilen zwischen Ihre Befehle zu setzen": Nein, dies funktioniert nur, weil das zuletzt interpretierte Zeichen der vorherigen Zeilen ist |. Wenn Sie es versuchen cat file1\<newline>#comment<newline>file2, werden Sie sehen, dass Sie nicht bekommen cat file1 file2, sondern cat file1; file2.
zweifelhafter
5
Wie andere bereits erwähnt haben, cat file1 | # comment<newline>sortfunktioniert dies jedoch einwandfrei. So auch cat file1 && # comment<newline>echo foo. Kommentare können also nach |oder &&oder ||eingefügt werden, jedoch nicht nach `\` oder mitten in einem Befehl.
Dubiousjim
7

Wie DigitalRoss hervorhob, ist der nachfolgende Backslash nicht erforderlich, wenn die Zeile enden würde |. Und Sie können Kommentare in eine Zeile einfügen, die a folgt |:

 cat ${MYSQLDUMP} |         # Output MYSQLDUMP file
 sed '1d' |                 # skip the top line
 tr ",;" "\n" | 
 sed -e 's/[asbi]:[0-9]*[:]*//g' -e '/^[{}]/d' -e 's/""//g' -e '/^"{/d' |
 sed -n -e '/^"/p' -e '/^print_value$/,/^option_id$/p' |
 sed -e '/^option_id/d' -e '/^print_value/d' -e 's/^"\(.*\)"$/\1/' |
 tr "\n" "," |
 sed -e 's/,\([0-9]*-[0-9]*-[0-9]*\)/\n\1/g' -e 's/,$//' |   # hate phone numbers
 sed -e 's/^/"/g' -e 's/$/"/g' -e 's/,/","/g' >> ${CSV}
Mob
quelle
5

Der Backslash entgeht dem # und interpretiert es als Literalzeichen anstelle eines Kommentarzeichens.

tobiasvl
quelle
3

$IFS Kommentar-Hacks

Dieser Hack verwendet die Parametererweiterung on $IFS, mit der Wörter in Befehlen getrennt werden:

$ echo foo${IFS}bar
foo bar

Ähnlich:

$ echo foo${IFS#comment}bar
foo bar

Auf diese Weise können Sie einen Kommentar in eine Befehlszeile mit der folgenden Bezeichnung einfügen:

$ echo foo${IFS# Comment here} \
> bar
foo bar

Der Kommentar muss jedoch vor der \Fortsetzung stehen.

Beachten Sie, dass die Parametererweiterung innerhalb des Kommentars durchgeführt wird:

$ ls file
ls: cannot access 'file': No such file or directory
$ echo foo${IFS# This command will create file: $(touch file)}bar
foo bar
$ ls file
file

Seltene Ausnahme

Der einzige seltene Fall, in dem dies fehlschlägt, ist, wenn $IFSzuvor mit dem genauen Text begonnen wurde, der über die Erweiterung entfernt wurde (dh nach dem #Zeichen):

$ IFS=x
$ echo foo${IFS#y}bar
foo bar
$ echo foo${IFS#x}bar
foobar

Beachten Sie, dass das Finale foobarkeinen Platz hat, um das Problem zu veranschaulichen.

Da $IFSstandardmäßig nur Leerzeichen enthalten sind, ist es äußerst unwahrscheinlich, dass Sie auf dieses Problem stoßen.


Dank an @ pjhs Kommentar, der diese Antwort ausgelöst hat.

Tom Hale
quelle
1

Zusätzlich zu den Beispielen von DigitalRoss gibt es hier ein weiteres Formular, das Sie verwenden können, wenn Sie $()anstelle von Backticks bevorzugen`

echo abc $(: comment) \
     def $(: comment) \
     xyz

Natürlich können Sie die Doppelpunktsyntax auch mit Backticks verwenden:

echo abc `: comment` \
     def `: comment` \
     xyz

Zusätzliche Bemerkungen

Der Grund, warum $(#comment)dies nicht funktioniert, ist #, dass der Rest der Zeile als Kommentar behandelt wird, einschließlich der schließenden Klammern : comment). Die Klammern werden also niemals geschlossen.

Backticks werden anders analysiert und erkennen den schließenden Backtick auch nach a #.

wisbucky
quelle
1
Wird dadurch für jeden Kommentar eine neue Shell erstellt?
Lonix
0

Hier ist ein Bash-Skript, das die Ideen und Redewendungen mehrerer vorheriger Kommentare kombiniert, um mit Beispielen Inline-Kommentare in der allgemeinen Form bereitzustellen ${__+ <comment text>}.

Bestimmtes

  • <comment text> kann mehrzeilig sein
  • <comment text> ist nicht parametererweitert
  • Es werden keine Unterprozesse erzeugt (Kommentare sind also effizient).

Es gibt eine Einschränkung <comment text>, nämlich, dass unausgeglichene Klammern '}'und Klammern ')'geschützt werden müssen (dh '\}'und '\)').

Es gibt eine Anforderung an die lokale Bash-Umgebung:

  • Der Parametername __muss nicht gesetzt sein

Jeder andere syntaktisch gültige Bash-Parametername wird anstelle von verwendet __, sofern der Name keinen festgelegten Wert hat.

Ein Beispielskript folgt

# provide bash inline comments having the form
#     <code> ${__+ <comment>} <code> 
#     <code> ${__+ <multiline
#                   comment>} <code>

# utility routines that obviate "useless use of cat"
function bashcat { printf '%s\n' "$(</dev/stdin)"; }
function scat { 1>&2 bashcat; exit 1; }

# ensure that '__' is unset && remains unset
[[ -z ${__+x} ]] &&  # if '__' is unset
  declare -r __ ||   # then ensure that '__' remains unset 
  scat <<EOF         # else exit with an error
Error: the parameter __='${__}' is set, hence the
  comment-idiom '\${__+ <comment text>}' will fail
EOF

${__+ (example of inline comments)
------------------------------------------------
the following inline comment-idiom is supported
    <code> ${__+ <comment>} <code> 
    <code> ${__+ <multiline
                  comment>} <code> 
(advisory) the parameter '__' must NOT be set;
  even the null declaration __='' will fail
(advisory) protect unbalanced delimiters \} and \) 
(advisory) NO parameter-expansion of <comment> 
(advisory) NO subprocesses are spawned
(advisory) a functionally equivalent idiom is 
    <code> `# <comment>` <code> 
    <code> `# <multiline
               comment>` <code>
however each comment spawns a bash subprocess
that inelegantly requires ~1ms of computation 
------------------------------------------------}
John Sidles
quelle