¿Qué caracteres se requieren para escapar en los argumentos de la línea de comandos?


14

En Bash, al especificar argumentos de línea de comando para un comando, ¿qué caracteres se necesitan para escapar?

Están limitados a los meta-caracteres de Bash: espacio, ficha, |, &, ;, (, ), <, y >?


No olvide (posible) el nombre de archivo global con * y?
Jeff Schaller

Gracias. ¿Podría enumerar exhaustivamente los tipos de caracteres que deben escaparse en los argumentos de línea cmd?
Tim

Es bueno tener la lista, pero lo más importante que hay que entender sobre las citas es : todo entre comillas simples se pasa literalmente y sin división de palabras. Sin excepciones. (Esto significa que no hay manera alguna para incrustar una comilla entre comillas simples, por cierto, pero que es fácil de trabajar alrededor .)
Comodín

Respuestas:


22

Los siguientes caracteres tienen un significado especial para el shell en algunos contextos y es posible que se deban escapar en argumentos:

Algunos de esos personajes se usan para más cosas y en más lugares que el que he vinculado.


Hay algunos casos de esquina que son explícitamente opcionales:

  • !se puede deshabilitar con set +H, que es el valor predeterminado en shells no interactivos.
  • {se puede deshabilitar con set +B.
  • *y ?se puede deshabilitar con set -foset -o noglob .
  • =El signo igual (U + 003D) también debe escaparse si está habilitado set -ko noset -o keyword .

Escapar de una nueva línea requiere una cita : las barras invertidas no harán el trabajo. Cualquier otro personaje listado en IFS necesitará un manejo similar. No necesita escapar ]o }, pero necesita escapar )porque es un operador.

Algunos de estos personajes tienen límites más estrictos sobre cuándo realmente necesitan escapar que otros. Por ejemplo, a#bestá bien, pero a #bes un comentario, aunque >necesitaría escapar en ambos contextos. De todos modos, no está de más escapar de todos de forma conservadora, y es más fácil que recordar las distinciones.

Si el nombre del comando en sí es una palabra clave de shell ( if, for, do), entonces tendrá que escapar o citar también. El único interesante de esos es in, porque no es obvio que siempre es una palabra clave. Usted no necesita hacer eso por palabras clave utilizadas en los argumentos, sólo cuando se haya (tontos!) Nombró a un comando de uno de ellos. Operadores de Shell ( (, &, etc.) siempre necesitan citando a donde quiera que estén.


1 Stéphane ha notado que cualquier otro carácter en blanco de un solo byte de su localidad también necesita escapar. En los entornos locales más comunes y sensibles, al menos aquellos basados ​​en C o UTF-8, son solo los caracteres de espacio en blanco anteriores. En algunas configuraciones regionales ISO-8859-1, el espacio sin interrupción U + 00A0 se considera en blanco, incluidos Solaris, los BSD y OS X (creo que es incorrecto). Si se trata de una configuración regional desconocida arbitraria, podría incluir casi cualquier cosa, incluidas letras, así que buena suerte.

Posiblemente, un solo byte considerado en blanco podría aparecer dentro de un carácter de varios bytes que no estaba en blanco, y no tendría forma de escapar de eso aparte de poner todo el asunto entre comillas. Esto no es una preocupación teórica: en un entorno local ISO-8859-1 desde arriba, ese A0byte que se considera en blanco puede aparecer dentro de caracteres multibyte como UTF-8 codificado "à" ( C3 A0). Para manejar esos caracteres de manera segura, deberá citarlos "à". Este comportamiento depende de la configuración regional en el entorno que ejecuta el script, no del lugar donde lo escribió.

Creo que este comportamiento se rompe de varias maneras, pero tenemos que jugar la mano que nos reparten. Si está trabajando con un conjunto de caracteres multibyte que no se sincroniza automáticamente, lo más seguro sería citar todo. Si estás en UTF-8 o C, estás a salvo (por el momento).


Otros espacios en blanco en su localidad también necesitarían escapar ( excepto actualmente el de varios bytes debido a un error )
Stéphane Chazelas

Solo necesita escapar !cuando la expansión del historial de csh está habilitada, generalmente no en scripts. [ ! -f a ]o find . ! -name...están bien Eso está cubierto por la sección de límites más estrictos, pero quizás valga la pena mencionarlo explícitamente.
Stéphane Chazelas

Tenga en cuenta que hay contextos donde otros personajes necesitan citando como: hash[foo"]"]=, ${var-foo"}"}, [[ "!" = b ]], [[ a = "]]" ]], los operadores de expresiones regulares para [[ x =~ ".+[" ]]. Otras palabras clave que {( if, while, for...) tendrían que ser citado para que no sean reconocidos como tales ...
Stéphane Chazelas

En la medida en que esos son argumentos de la línea de comandos, la interpretación depende del comando en cuestión (al igual que ]), por lo que no los enumero. No creo que ninguna palabra clave necesite ser citada en la posición del argumento.
Michael Homer

2
Citar builtins, guiones o% no hace nada.
Michael Homer

3

En GNU Parallel esto se prueba y se usa ampliamente:

$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'                                                                                                         
$a =~ s/[\n]/'\n'/go;

Se ensayó en bash, dash, ash, ksh, zsh, y fish. Algunos de los personajes no necesitan comillas en algunas (versiones) de los shells, pero lo anterior funciona en todos los shells probados.

Si simplemente desea una cadena entre comillas, puede canalizarla en parallel --shellquote:

printf "&*\t*!" | parallel --shellquote

¿Cómo no he oído hablar de paralelo antes ...
Tom H

@TomH Se agradece si puede pasar 5 minutos pensando en cómo podríamos haberlo contactado.
Ole Tange

Creo que es un problema de progresión. la mayoría de las personas no necesitan ni entienden en paralelo hasta que hayan progresado en algunas etapas complejas. En ese momento se han encontrado con xargs, nohup y cosas así. Además, no veo a muchas personas que utilicen el paralelo para resolver problemas en el intercambio de pila o cuando busco en Google soluciones a problemas de bash
Tom H

1

Para una solución de escape ligera en Perl, estoy siguiendo el principio de comillas simples. Un Bash-string en comillas simples puede tener cualquier carácter, excepto la comilla simple en sí.

Mi código:

my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);

while(<>) {
    if (/$bash_reserved_characters_re/) {
        my $quoted = s/'/'"'"'/gr;
        print "'$quoted'";
    } else {
        print $_;
    }
}

Ejemplo de ejecución 1:

$ echo -n "abc" | perl escape_bash_special_chars.pl
abc

Ejemplo de ejecución 2:

echo "abc" | perl escape_bash_special_chars.pl
'abc
'

Ejemplo de ejecución 3:

echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c

Ejemplo de ejecución 4:

echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'

Ejemplo de ejecución 5:

echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'

echo 'ab'"'"'c'
ab'c

Sí, punto válido eso. Mi opinión es que la mayoría de las personas aterrizarán en esta página, porque tienen un problema que resolver. No porque esto haga un interesante debate académico. Es por eso que me gustaría ofrecer soluciones y discutir los méritos de ellas, incluso estando un poco fuera de tema.
Jari Turkia

Mi código es solo una implementación de la respuesta de Michael Homer. No intenté traer más información de la que él hizo.
Jari Turkia
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.