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:
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 sí 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).
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:
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:
@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 $_;}}
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.
Respuestas:
Los siguientes caracteres tienen un significado especial para el shell en algunos contextos y es posible que se deban escapar en argumentos:
`
Backtick (U + 0060 Acento grave)~
Tilde (U + 007E)!
Signo de exclamación (U + 0021)#
Hash (U + 0023 Signo de número)$
Signo de dólar (U + 0024)&
Ampersand (U + 0026)*
Asterisco (U + 002A)(
Paréntesis izquierdo (U + 0028))
Paréntesis derecho (U + 0029)(
⇥
) Pestaña (U + 0009){
Tirante izquierdo (U + 007B Soporte rizado izquierdo)[
Soporte cuadrado izquierdo (U + 005B)|
Barra vertical (línea vertical U + 007C)\
Backslash (U + 005C Solidus inversa);
Punto y coma (U + 003B)'
Presupuesto simple / Apostrophe (U + 0027)"
Comilla doble (U + 0022)↩
Nueva línea (U + 000A)<
Menos de (U + 003C)>
Mayor que (U + 003E)?
Signo de interrogación (U + 003F)Espacio (U + 0020) 1
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 conset +H
, que es el valor predeterminado en shells no interactivos.{
se puede deshabilitar conset +B
.*
y?
se puede deshabilitar conset -f
oset -o noglob
.=
El signo igual (U + 003D) también debe escaparse si está habilitadoset -k
o 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 sí 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#b
está bien, peroa #b
es 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 esin
, 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
A0
byte 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).
fuente
!
cuando la expansión del historial de csh está habilitada, generalmente no en scripts.[ ! -f a ]
ofind . ! -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.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 ...]
), por lo que no los enumero. No creo que ninguna palabra clave necesite ser citada en la posición del argumento.En GNU Parallel esto se prueba y se usa ampliamente:
Se ensayó en
bash
,dash
,ash
,ksh
,zsh
, yfish
. 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
:fuente
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:
Ejemplo de ejecución 1:
Ejemplo de ejecución 2:
Ejemplo de ejecución 3:
Ejemplo de ejecución 4:
Ejemplo de ejecución 5:
fuente