Comentando en un script Bash dentro de un comando multilínea

164

¿Cómo puedo comentar en cada línea de las siguientes líneas de 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 intento agregar un comentario como:

cat ${MYSQLDUMP} | \ # Output MYSQLDUMP File

Yo obtengo:

#: not found

¿Es posible comentar aquí?

BassKozz
fuente
1
Bueno, como notó, si hace # primero, entonces el \ se convierte en parte del comentario, pero si lo hace primero, los caracteres posteriores en la línea cambian su significado de "continuación de línea" a "cita". He pensado en una solución, dada a continuación.
DigitalRoss

Respuestas:

203

Esto tendrá algunos gastos generales, pero técnicamente responde a su pregunta:

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

Y para las tuberías específicamente, hay una solución limpia sin gastos generales:

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

Consulte la pregunta de desbordamiento de pila Cómo colocar comentarios de línea para un comando de varias líneas .

DigitalRoss
fuente
1
Parece bastante complejo, si no hay un método más simple?
BassKozz
1
Ok, he agregado una variación un poco más simple.
DigitalRoss
1
¿Puedes modificar tu respuesta solo para mostrar el hecho de que la barra invertida no es necesaria para que pueda poner los comentarios al lado de cada línea y simplemente usar una tubería?
BassKozz
Verifiqué que las versiones uno y dos funcionan. Sin embargo, ¿puede explicar por qué lo hacen y qué está pasando aquí? Gracias.
Faheem Mitha
1
Gracias por la explicación. He abierto una pregunta en unix.sx pidiendo más detalles, bash comando de varias líneas con comentarios después del carácter de continuación .
Faheem Mitha
39

La barra invertida final debe ser el último carácter de la línea para que se interprete como un comando de continuación. No se permiten comentarios ni espacios en blanco después.

Debería poder poner líneas de comentario entre sus comandos

# 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}
multitud
fuente
12
El \ no es necesario cuando el componente de comando de canalización termina con |
DigitalRoss
2
DigitalRoss, tienes razón, solo puedo usar la tubería y no la barra diagonal inversa y luego mis # comentarios funcionarán perfectamente ... ¿puedes publicar eso como respuesta para que pueda aceptarlo?
BassKozz
8
"Debería poder poner líneas de comentario entre sus comandos": no, esto solo funciona porque el último carácter interpretado de las líneas anteriores es |. Si lo intentas cat file1\<newline>#comment<newline>file2, verás que no entiendes cat file1 file2, sino más bien cat file1; file2.
dubiousjim
55
Sin embargo, como otros han mencionado, cat file1 | # comment<newline>sortfunciona bien. También lo hace cat file1 && # comment<newline>echo foo. Por lo tanto, los comentarios se pueden incluir después de |o &&o ||, pero no después de `\` o en medio de un comando.
dudoso
7

Como señaló DigitalRoss, la barra diagonal inversa no es necesaria cuando la línea termina |. Y puede poner comentarios en una línea que sigue 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}
multitud
fuente
5

La barra diagonal inversa escapa al #, interpretándolo como su carácter literal en lugar de un carácter de comentario.

tobiasvl
fuente
3

$IFS hacks de comentarios

Este truco usa la expansión de parámetros en $IFS, que se usa para separar palabras en comandos:

$ echo foo${IFS}bar
foo bar

Similar:

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

Con esto, puede poner un comentario en una línea de comando con continuación:

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

pero el comentario deberá ser antes de la \continuación.

Tenga en cuenta que la expansión de parámetros se realiza dentro del comentario:

$ 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

Rara excepción

El único caso raro en el que esto falla es si $IFSse inició previamente con el texto exacto que se elimina mediante la expansión (es decir, después del #carácter):

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

Tenga en cuenta que la final foobarno tiene espacio, lo que ilustra el problema.

Como $IFScontiene solo espacios en blanco de forma predeterminada, es extremadamente improbable que se encuentre con este problema.


Crédito para el comentario de @ PJH que desencadenó esta respuesta.

Tom Hale
fuente
1

Además de los ejemplos de DigitalRoss, aquí hay otra forma que puedes usar si lo prefieres en $()lugar de backticks`

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

Por supuesto, también puede usar la sintaxis de colon con comillas inversas:

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

Notas adicionales

La razón por la $(#comment)que no funciona es porque una vez que ve el #, trata el resto de la línea como comentarios, incluyendo el cierre de paréntesis: comment). Entonces los paréntesis nunca se cierran.

Los backticks se analizan de manera diferente y detectarán el backtick de cierre incluso después de a #.

wisbucky
fuente
1
¿Creará eso un nuevo shell para cada comentario?
lonix
0

Aquí hay un script bash que combina las ideas y expresiones idiomáticas de varios comentarios anteriores para proporcionar, con ejemplos, comentarios en línea que tienen la forma general ${__+ <comment text>}.

En particular

  • <comment text> puede ser multilínea
  • <comment text> no está expandido por parámetros
  • no se generan subprocesos (por lo que los comentarios son eficientes)

Hay una restricción sobre <comment text>, a saber, los paréntesis '}'y los corchetes desequilibrados ')'deben protegerse (es decir, '\}'y '\)').

Hay un requisito en el entorno bash local:

  • el nombre del parámetro __debe estar desarmado

Cualquier otro nombre de parámetro bash sintácticamente válido servirá en lugar de __ , siempre que el nombre no tenga un valor establecido.

Sigue un script de ejemplo

# 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
fuente