Solo una nota adicional sobre la excelente respuesta de @ Kusalananda .
echo run after_bundle
está bien porque ninguno de los caracteres en esos 3 argumentos¹ pasados para echo
contener caracteres que son especiales para el shell.
Y (el punto extra que quiero destacar aquí) no hay una configuración regional del sistema donde esos bytes puedan traducirse a caracteres que sean especiales para el shell.
Todos esos caracteres están en lo que POSIX llama el juego de caracteres portátil . Esos caracteres deben estar presentes y codificados de la misma manera en todos los juegos de caracteres en un sistema POSIX².
De modo que esa línea de comando se interpretará de la misma forma independientemente de la configuración regional.
Ahora, si comenzamos a usar caracteres fuera de ese conjunto de caracteres portátil, es una buena idea citarlos incluso si no son especiales para el shell, porque en otro entorno local, los bytes que los constituyen pueden interpretarse como caracteres diferentes que podrían convertirse en especial a la concha. Tenga en cuenta que es si está utilizando echo
o cualquier otro comando, el problema no es echo
con la forma en que el shell analiza su código.
Por ejemplo en un UTF-8:
echo voilà | iconv -f UTF-8 -t //TRANSLIT
Eso à
está codificado como 0xc3 0xa0. Ahora, si tiene esa línea de código en una secuencia de comandos de shell y la secuencia de comandos de shell es invocada por un usuario que utiliza una configuración regional cuyo conjunto de caracteres no es UTF-8, esos dos bytes podrían tener caracteres muy diferentes.
Por ejemplo, en un fr_FR.ISO8859-15
entorno local, un entorno local típico francés que utiliza el juego de caracteres estándar de un solo byte que cubre el idioma francés (el mismo que se usa para la mayoría de los idiomas de Europa occidental, incluido el inglés), ese byte 0xc3 se interpreta como el Ã
carácter y 0xa0 como el no Rompiendo el carácter del espacio.
Y en algunos sistemas como NetBSD³, ese espacio que no se rompe se considera como un carácter en blanco ( isblank()
en él devuelve verdadero, coincide con [[:blank:]]
) y los shells como, bash
por lo tanto, lo tratan como un delimitador de token en su sintaxis.
Esto significa que en lugar de correr echo
con $'voil\xc3\xa0'
como argumento, se ejecutan con $'voil\xc3'
como argumento, lo que significa que no se imprimirá voilà
correctamente.
Se pone mucho peor con los juegos de caracteres chinos como Big5, Big5-HKSCS, GB18030, GBK que tienen muchos personajes cuya codificación contiene la misma codificación que el |
, `
, \
(por nombrar el peor) (también que SJIS ridícula, también conocido como Microsoft kanji, excepto que es en ¥
lugar de \
, pero aún así es tratado \
por la mayoría de las herramientas ya que está codificado como 0x5c allí).
Por ejemplo, si está en un zh_CN.gb18030
entorno chino, escribe un script como:
echo 詜 reboot
Ese script se generará 詜 reboot
en un entorno local utilizando GB18030 o GBK, 唰 reboot
en un entorno local utilizando BIG5 o BIG5-HKSCS, pero en un entorno local C utilizando ASCII o un entorno local utilizando ISO8859-15 o UTF-8, se reboot
ejecutará porque la codificación GB18030 de 詜
es 0xd4 0x7c y 0x7c es la codificación de |
ASCII, por lo que terminamos ejecutando:
echo �| reboot
(que representa sin embargo el byte 0xd4 se representa en la configuración regional). Ejemplo usando el menos dañino en uname
lugar de reboot
:
$ echo $'echo \u8a5c uname' | iconv -t gb18030 > myscript
$ LC_ALL=zh_CN.gb18030 bash ./myscript | sed -n l
\324| uname$
$ LC_ALL=C bash ./myscript | sed -n l
Linux$
( uname
Se corrió).
Por lo tanto, mi consejo sería citar todas las cadenas que contienen caracteres fuera del conjunto de caracteres portátil.
Sin embargo, tenga en cuenta que, dado que la codificación de \
y `
se encuentra en la codificación de algunos de esos caracteres, es mejor no usar \
o "..."
o $'...'
(dentro de los cuales `
y / o \
todavía son especiales), sino '...'
citar caracteres fuera del conjunto de caracteres portátil.
No conozco ningún sistema que tenga una configuración regional donde el juego de caracteres tenga algún carácter (aparte de '
sí mismo, por supuesto) cuya codificación contenga la codificación '
, por lo '...'
que definitivamente debería ser el más seguro.
Tenga en cuenta que varios shells también admiten una $'\uXXXX'
notación para expresar caracteres en función de su punto de código Unicode. En shells como zsh
y bash
, el carácter se inserta codificado en el juego de caracteres de la configuración regional (aunque puede causar comportamientos inesperados si ese juego de caracteres no tiene ese carácter). Eso le permite evitar insertar caracteres no ASCII en su código de shell.
Así arriba:
echo 'voilà' | iconv -f UTF-8 -t //TRANSLIT
echo '詜 reboot'
O:
echo $'voil\u00e0'
echo $'\u8a5c reboot'
(con la advertencia, podría romper el script cuando se ejecuta en entornos locales que no tienen esos caracteres).
O mejor, ya \
que también es especial para echo
(o al menos algunas echo
implementaciones, al menos las que cumplen con Unix):
printf '%s\n' 'voilà' | iconv -f UTF-8 -t //TRANSLIT
printf '%s\n' '詜 reboot'
(tenga en cuenta que \
también es especial en el primer argumento printf
, por lo que también es mejor evitar los caracteres no ASCII en caso de que puedan contener la codificación de \
).
Tenga en cuenta que también puede hacer:
'echo' 'voilà' | 'iconv' '-f' 'UTF-8' '-t' '//TRANSLIT'
(eso sería excesivo, pero podría darte un poco de tranquilidad si no estás seguro de qué personajes están en el conjunto de caracteres portátil)
Además, asegúrese de nunca usar la antigua `...`
forma de sustitución de comandos (que introduce otro nivel de procesamiento de barra invertida), pero en su $(...)
lugar use .
¹ técnicamente, echo
también se pasa como argumento a la echo
utilidad (a decirle cómo se invoca), que es el argv[0]
y argc
es 3, aunque en la mayoría de las conchas hoy en día echo
se orden interna, de manera que exec()
de un /bin/echo
archivo con una lista de 3 argumentos es simulado por el cáscara. También es común considerar que la lista de argumentos comienza con el segundo ( argv[1]
to argv[argc - 1]
), ya que es sobre los que actúan principalmente los comandos.
² ¡una notable excepción a que es la ridícula ja_JP.SJIS
localización de los sistemas FreeBSD cuyo juego de caracteres no tiene \
ni ~
carácter!
³ tenga en cuenta que si bien muchos sistemas (FreeBSD, Solaris, no GNU) consideran U + 00A0 como [[:blank:]]
en configuraciones regionales UTF-8, pocos lo hacen en otras configuraciones regionales como las que usan ISO8859-15, posiblemente para evitar este tipo de problema.