Comentarios de script de shell multilínea: ¿cómo funciona esto?

92

Recientemente, me topé con un tipo de comentario de varias líneas que nunca había visto antes; aquí hay un ejemplo de script:

echo a
#
: aaa 
: ddd 
#
echo b

Esto parece funcionar, incluso la vimsintaxis lo resalta. ¿Cómo se llama este estilo de comentarios y cómo puedo encontrar más información al respecto?

Wiesław Herr
fuente
1
¿Qué sucede si, en cambio, envuelve su código en función para comentarlo? CommentedOutBlock() { echo "test"; }
Buksy el

Respuestas:

135

Ese no es un comentario de varias líneas. #es un comentario de una sola línea :(dos puntos) no es un comentario en absoluto, sino más bien un comando incorporado de shell que es básicamente un NOP , una operación nula que no hace nada excepto devolver true, like true(y, por lo tanto, establecer $?a 0 como efecto secundario). Sin embargo, dado que es un comando, puede aceptar argumentos, y dado que ignora sus argumentos, en la mayoría de los casos actúa superficialmente como un comentario. El principal problema con este error es que los argumentos aún se expanden, lo que lleva a una serie de consecuencias no deseadas. Los argumentos todavía se ven afectados por los errores de sintaxis, las redirecciones aún se realizan, por lo que : > filese truncarán filey las : $(dangerous command)sustituciones se seguirán ejecutando.

La forma menos segura y sorprendente de insertar comentarios en los scripts de shell es con #. Apéguese a eso incluso para comentarios de varias líneas. Nunca intente (ab) usarlo :para comentarios. No hay un mecanismo de comentarios de varias líneas dedicado en el shell que sea análogo a la forma de barra diagonal /* */en Clenguajes similares.


En aras de la exhaustividad, pero no porque sea una práctica recomendada, mencionaré que es posible utilizar documentos aquí para hacer "comentarios" de varias líneas:

: <<'end_long_comment'
This is an abuse of the null command ':' and the here-document syntax
to achieve a "multi-line comment".  According to the POSIX spec linked 
above, if any character in the delimiter word ("end_long_comment" in 
this case) above is quoted, the here-document will not be expanded in 
any way.  This is **critical**, as failing to quote the "end_long_comment" 
will result in the problems with unintended expansions described above. 
All of this text in this here-doc goes to the standard input of :, which 
does nothing with it, hence the effect is like a comment.  There is very 
little point to doing this besides throwing people off.  Just use '#'.
end_long_comment
jw013
fuente
29
+1 es muy importante para mantener las comillas simples en la <<línea, lo que desactiva la sustitución y la expansión.
Glenn Jackman
44
Y como nota adicional, llenar scripts de shell con :cosas que deberían ser comentarios causará un consumo adicional de RAM / CPU. No importará cosas simples en tu escritorio, pero si es algo ejecutado cientos o miles de veces por segundo, no harás nada, muy rápido .
bahamat
3
@bahamat: si ejecuta algo cientos o miles de veces por segundo, espero que no lo escriba en shell ... = /
7heo.tk
1
A veces, puede ser útil usar la utilidad nula para varias líneas de texto. Comenzar el comentario con : <<=cuthace posible escribir POD en scripts de shell, vea este ejemplo para más detalles . Esto hace posible su uso perldoc script.sh. Sin embargo, el comentario de varias líneas que se muestra en esta respuesta es algo que definitivamente debería ser un bloque de comentarios (cada línea comienza con # ).
basic6
Aquí hay una buena discusión sobre heredocs, utilizada tanto para comentarios como para otros casos de uso interesantes (incluso incluyendo la generación de script dynaimc): tldp.org/LDP/abs/html/here-docs.html#EX71C
bguiz
28

No es ningún estilo de comentario. el :comando incorporado no hace absolutamente nada; se está abusando de comentar aquí.

$ help :
:: :
    Null command.

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.
Ignacio Vazquez-Abrams
fuente
25

En los primeros depósitos, el colon era la única forma de crear comentarios.

Sin embargo, no es un comentario verdadero, porque la línea se analiza exactamente de la misma manera que cualquier otro comando, y eso puede tener efectos secundarios. Por ejemplo:

: ${a:=x} # assigns the value 'x' to the variable, 'a'

: $(command) # executes 'command'

(A veces, el colon se usa únicamente con el fin de invocar esos efectos secundarios, pero luego no se usa como comentario).

A veces es conveniente usar los dos puntos para comentar una sección de un script:

: '
while [ "$n" -ne "$x" ]
do
  : whatever
done
'

Esto es un gran ahorro de tiempo sobre el precedente de cada línea #, particularmente si el comentario es solo temporal.

Chris FA Johnson
fuente
2
Ese método de comentario de comillas simples no funciona en ninguna sección del script que en sí utiliza comillas simples. Y si está usando comillas en cualquier lugar cercano a lo que debería, eso significa que tendrá comillas simples legítimas esparcidas a lo largo de todo el script. Es mucho más simple usar cualquier editor decente que le permita bloquear comentarios linealmente.
jw013
Tiene toda la razón en que solo funcionará si no hay comillas simples en la sección citada. Sin embargo, un script no necesita tener muchas comillas simples. Al revisar algunos de mis scripts, los encuentro relativamente escasos, y muchos podrían ser reemplazados por comillas dobles.
Chris FA Johnson
La elección de comillas simples o comillas dobles no debería verse influenciada por algo tan trivial e irrelevante como si el texto de su script es en sí mismo una cadena válida entre comillas simples. Las comillas simples se usan para evitar expansiones, mientras que las comillas dobles permiten ciertas expansiones y requieren un análisis adicional. Este es el criterio real para determinar cuál usar.
jw013
Esta es, con mucho, la forma más elegante de hacerlo. Ideal para pequeños bloques de documentación. Me gusta más que /* */y ugh, ¡no me hagas comenzar <!-- -->!
alex gray
1

Si su comentario está al final del guión, puede hacerlo así:

#!/bin/sh
echo 'hello world'
exec true
we can put whatever we want here
\'\"\$\`!#%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
abcdefghijklmnopqrstuvwxyz{|}~
Steven Penny
fuente