Commenter dans un script Bash dans une commande multiligne

165

Comment puis-je commenter chaque ligne des lignes suivantes d'un script?

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}

Si j'essaye d'ajouter un commentaire comme:

cat ${MYSQLDUMP} | \ # Output MYSQLDUMP File

Je reçois:

#: not found

Est-il possible de commenter ici?

BassKozz
la source
1
Eh bien, comme vous l'avez remarqué, si vous faites # d'abord, alors le \ devient juste une partie du commentaire, mais si vous faites \ d'abord, alors les derniers caractères de la ligne changent sa signification de "continuation de ligne" à "guillemet". J'ai pensé à une solution, donnée ci-dessous.
DigitalRoss
1
duplication possible de Comment mettre un commentaire de ligne pour une commande
multiligne

Réponses:

204

Cela entraînera des frais généraux, mais techniquement, cela répond à votre question:

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

Et pour les pipelines en particulier, il existe une solution propre sans frais généraux:

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

Voir la question de débordement de pile Comment insérer un commentaire de ligne pour une commande multiligne .

DigitalRoss
la source
1
Cela semble assez complexe, s'il n'y a pas de méthode plus simple?
BassKozz
1
Ok, j'ai ajouté une variante un peu plus simple.
DigitalRoss
1
Pouvez-vous modifier votre réponse juste pour montrer le fait que la barre oblique inverse n'est pas nécessaire afin que je puisse mettre les commentaires à côté de chaque ligne et simplement utiliser un tube?
BassKozz
J'ai vérifié que les versions un et deux fonctionnent. Cependant, pouvez-vous expliquer pourquoi ils le font et ce qui se passe ici? Merci.
Faheem Mitha
1
Merci pour l'explication. J'ai ouvert une question sur unix.sx demandant plus de détails, bash commande multi-lignes avec des commentaires après le caractère de continuation .
Faheem Mitha
39

La barre oblique inverse de fin doit être le dernier caractère de la ligne pour qu'elle soit interprétée comme une commande de continuation. Aucun commentaire ou même espace blanc n'est autorisé après.

Vous devriez pouvoir mettre des lignes de commentaires entre vos commandes

# 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}
foule
la source
12
Le \ n'est pas nécessaire lorsque le composant de commande de pipeline se termine par |
DigitalRoss
2
DigitalRoss, vous avez raison, je peux simplement utiliser le tube et non la barre oblique inverse, puis mes #commentaires fonctionneront parfaitement ... pouvez-vous poster cela comme une réponse afin que je puisse l'accepter.
BassKozz
8
"Vous devriez pouvoir mettre des lignes de commentaires entre vos commandes": non, cela ne fonctionne que parce que le dernier caractère interprété des lignes précédentes l'est |. Si vous essayez cat file1\<newline>#comment<newline>file2, vous verrez que vous n'obtenez pas cat file1 file2, mais plutôt cat file1; file2.
dubiousjim
5
Cependant, comme d'autres l'ont mentionné, cat file1 | # comment<newline>sortfonctionne très bien. Il en va de même cat file1 && # comment<newline>echo foo. Ainsi, les commentaires peuvent être inclus après |ou &&ou ||, mais pas après `\` ou au milieu d'une commande.
dubiousjim
7

Comme l'a souligné DigitalRoss, la barre oblique inverse de fin n'est pas nécessaire lorsque la ligne se termine |. Et vous pouvez mettre des commentaires sur une ligne suivant a |:

 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}
foule
la source
5

La barre oblique inverse échappe le #, l'interprétant comme son caractère littéral au lieu d'un caractère de commentaire.

tobiasvl
la source
3

$IFS hacks de commentaires

Ce hack utilise l' expansion des paramètres sur $IFS, qui est utilisé pour séparer les mots dans les commandes:

$ echo foo${IFS}bar
foo bar

De même:

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

En utilisant cela, vous pouvez mettre un commentaire sur une ligne de commande avec contination:

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

mais le commentaire devra être avant la \suite.

Notez que l'expansion des paramètres est effectuée à l'intérieur du commentaire:

$ 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

Exception rare

Le seul cas rare d'échec est s'il a $IFSdéjà commencé avec le texte exact qui est supprimé via l'expansion (c'est-à-dire après le #caractère):

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

Notez que la finale foobarn'a pas d'espace, illustrant le problème.

Comme $IFSne contient que des espaces par défaut, il est extrêmement peu probable que vous rencontriez ce problème.


Crédit commentaire de @ PJH qui a déclenché cette réponse.

Tom Hale
la source
1

En plus des exemples de DigitalRoss, voici un autre formulaire que vous pouvez utiliser si vous préférez à la $()place des backticks`

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

Bien sûr, vous pouvez également utiliser la syntaxe deux-points avec des backticks:

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

Notes complémentaires

La raison $(#comment)ne fonctionne pas est parce qu'une fois qu'il voit le #, il traite le reste de la ligne sous forme de commentaires, y compris les parenthèses de clôture: comment). Ainsi, les parenthèses ne sont jamais fermées.

Les backticks analysent différemment et détectent le backtick de fermeture même après un #.

wisbucky
la source
1
Cela créera-t-il un nouveau shell pour chaque commentaire?
lonix
0

Voici un script bash qui combine les idées et les idiomes de plusieurs commentaires précédents pour fournir, avec des exemples, des commentaires en ligne ayant la forme générale ${__+ <comment text>}.

En particulier

  • <comment text> peut être multiligne
  • <comment text> n'est pas étendu par paramètre
  • aucun sous-processus n'est généré (les commentaires sont donc efficaces)

Il y a une restriction sur le <comment text>, à savoir, les accolades '}'et les parenthèses non équilibrées ')'doivent être protégées (c'est-à-dire '\}'et '\)').

Il y a une exigence sur l'environnement bash local:

  • le nom du paramètre __doit être annulé

Tout autre nom de paramètre bash syntaxiquement valide servira à la place de __, à condition que le nom n'ait pas de valeur définie.

Un exemple de script suit

# 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
la source