bash: cómo pasar argumentos de línea de comando que contienen caracteres especiales

26

Me he escrito un programa de linux. program que necesita una expresión regular como entrada.

Quiero llamar al programa en el bash shell y pase esa expresión regular como un argumento de línea de comando al programa (también hay otros argumentos de línea de comando). Una expresión regular típica parece

[abc]\_[x|y]

Desafortunadamente los personajes [, ]y | son caracteres especiales en bash. Por lo tanto, llamando

program [abc]\_[x|y] anotheragument

no funciona ¿Hay alguna forma de pasar la expresión usando algún tipo de caracteres de escape o comillas, etc.?

(Vocación program "[abc]\_[x|y] anotheragument" Tampoco funciona, porque interpreta los dos argumentos como uno.

Christian
fuente

Respuestas:

22

Tu también puedes

  1. Escape cada uno de los símbolos especiales con una barra invertida (como en \[abc\]_\[x\|y\] ) o
  2. Cita doble el argumento completo (como en "[abc]_[x|y]" ).

EDITAR: Como algunos han señalado, el dobleqouting no impide la expansión de variables ni la sustitución de comandos. Por lo tanto, si su expresión regular contiene algo que bash puede interpretar como uno de esos, usar comillas simples en lugar.

U-D13
fuente
4
En bash, la doble cita hace no evitar las variables de expansión "$HOME" o parámetros "${USER:-root}", sustitución de comandos en cualquier forma "$(date)" o "`date`"expansión aritmética "$((1 + 2))"expansión de la historia "!!" o barra invertida de escape "\\". Utilice comillas simples en su lugar. Consulte la página de manual del manual de bash, la sección titulada "Cotización".
Flimm
24

Utilice comillas simples. Las comillas simples aseguran que ninguno de los caracteres sea interpretado.

$ printf %s 'spaces  are  not  interpreted away
neither are new lines
nor variable names $TESTING
nor square brackets [TESTING]
nor pipe characters or redirection symbols | > <
nor the semicolon ;
nor backslashes \a \b \c \\
the only thing that does not work is the single quote itself
'

Hay dos soluciones si necesita insertar una sola cita:

$ printf '%s\n' '[ Don'"'"'t worry, be happy! ]'
[ Don't worry, be happy! ]
$ printf '%s\n' '[ Don'\''t worry, be happy! ]'
[ Don't worry, be happy! ]
Flimm
fuente
Estás en lo correcto. +1
U-D13
6

Por man bash

Hay tres mecanismos de cotización:   la Personaje de escape , comillas simples,   y comillas dobles.

Una barra invertida no cotizada ( \ ) es el Personaje de escape . Conserva la   valor literal del siguiente caracter   A continuación, con la excepción de   & lt; nueva línea & gt ;. Si un \ & lt; nueva línea & gt; par   aparece, y la barra invertida no es   citado, el \ & lt; nueva línea & gt; es   tratado como una continuación de línea (que   Es decir, se elimina de la entrada.   transmitir y efectivamente ignorado).

Incluyendo caracteres en comillas simples   conserva el valor literal de cada   personaje dentro de las comillas. UNA   comilla simple no puede ocurrir entre   comillas simples, incluso cuando están precedidas por una   barra invertida

Incluyendo personajes en doble   comillas conserva el valor literal de   todos los caracteres dentro de las comillas, con   la excepción de PS , ` , \ , y cuando   la expansión de la historia está habilitada, ! . los   caracteres PS y ` retener su   Significado especial dentro de las comillas dobles.   La barra invertida conserva su especialidad.   significado solo cuando es seguido por uno de   los siguientes caracteres: PS , ` , " , \ o & lt; nueva línea & gt; . Una doble comilla puede   ser citado entre comillas dobles por   precediéndolo con una barra invertida. Si   habilitado, la expansión de la historia será   realizado a menos que un ! apareciendo en   comillas dobles se escapa utilizando una   barra invertida La barra invertida que precede   la ! no se elimina.

Los parametros especiales * y @ tener   significado especial cuando en comillas dobles   (ver Los parámetros abajo).

Palabras de la forma PS cuerda ' son   tratado especialmente. La palabra se expande   a cuerda , con barra invertida-escapó   caracteres reemplazados según lo especificado por   El estándar ANSI C. Escape de barra invertida   Las secuencias, si están presentes, se decodifican como   sigue:

        \una  alerta (campana)  \segundo  retroceso  \mi 
        \MI  un personaje de escape  \F  form feed  \norte  nueva línea  \ r  retorno de carro  \ t  pestaña horizontal  \ v  pestaña vertical  \\  barra invertida  \ '  una frase  \ "  doble cita  \  nnn  el carácter de ocho bits cuyo valor es el valor octal  nnn  (de uno a tres dígitos)  \X  S.S  el carácter de ocho bits cuyo valor es el valor hexadecimal  S.S  (uno o dos dígitos hexadecimales)  \ u  HHHHH  el carácter Unicode (ISO / IEC 10646) cuyo valor es
              el valor hexadecimal  HHHHH  (de uno a cuatro dígitos hexadecimales)  \ U  HHHHHHHHH  el carácter Unicode (ISO / IEC 10646) cuyo valor es
              el valor hexadecimal  HHHHHHHHH  (de uno a ocho dígitos hexadecimales)  \do  X  un control-  X  personaje 

El resultado expandido es de una sola cita,   Como si el signo del dólar no hubiera sido   presente.

Una cadena entre comillas dobles precedida por una   signo de dólar ( PS cuerda " ) causará la   cadena a traducir de acuerdo a   el local actual. Si el actual   locale es do o POSIX , el signo de dólar   se ignora Si la cadena es   traducido y reemplazado, el   el reemplazo es de doble cita.

Evan Carroll
fuente
2

Puede utilizar una barra invertida ( \ ) delante de personajes especiales para escapar de ellos así:

john@awesome:~ # echo \&
&
John T
fuente
2

Aunque podría no ser útil como una expresión regular, algunas secuencias de caracteres pueden interpretarse como nombres de variables Bash. Para evitar que esto ocurra y evitar que se expandan, use comillas simples en lugar de comillas dobles:

program '[abc]_[x|y]' anotherargument

Cita cada argumento por separado (si es que necesitan una cita) para que sean interpretados como argumentos independientes. También puedes usar matrices en algunos casos:

param_array=('[abc]_[x|y]' anotherargument)    # create an array
param_array+=(yetanother)     # append another element to the array
program "${param_array[@]}"   # use the array elements as arguments to program
Dennis Williamson
fuente
1
program "[abc]_[x|y]"
program "[abc]_[x|y]" anotherargument
Witek
fuente
0

Escapar de ellos debería funcionar bien:

  programm \[abc\]_\[x\|y\]
Bobby
fuente
0

¿De dónde viene el patrón? ¿Es fijo o es de un usuario? ¿Es el usuario el que invoca el script en el sistema local o alguien remoto?

Utiliza comillas para envolver los datos para evitar que el shell los interprete. Hay dos opciones:

  1. Comillas dobles, que todavía permiten cierta interpretación ($ expand y `backticks`)
  2. Comillas simples, que pasan todo literalmente

Porque $ es un carácter válido en las expresiones regulares (final de línea / búfer) que probablemente desee usar comillas simples para mantener la expresión regular, a menos que esté almacenado en una variable. Si está tomando datos arbitrarios de alguien que no es de confianza, deberá reemplazar ' con '"'"' y luego envolver en comillas simples.

Tenga en cuenta que [abc]_[x|y] parece que quieres emparejar x o y, mientras que en realidad coincide con uno de los tres personajes xy|. Los corchetes coinciden con los caracteres dentro y solo - para rangos y un ^ Al comienzo de la negación. Asi que, [abc]_(x|y) puede ser lo que quisiste decir, y los paréntesis son los caracteres que son especiales para el shell. Los corchetes son no Especial para shell, solo parece que son. Doble corchetes [[ ... ]] son especiales

Phil P
fuente
Esta es una de las respuestas más correctas aquí (agradezco especialmente las instrucciones para reemplazar ' con '"'"' ), sin embargo, todavía no es correcto. [ ES un carácter especial para shell, se usa en comodines cuando se realiza path-expansion (que shell hace para todo lo que no está entre comillas).
jpalecek
Es especial en algunos contextos, como la creación de subíndices variables o para los globos, pero aún puede escribir foo=a[b] y entonces echo $foo y ver que la cadena no necesitaba citarse. Tienes razón, fui demasiado breve.
Phil P
Si no tienes suerte, hay un archivo ab en el directorio actual, y luego foo contendrá ab más bien que a[b]. Cita tus corchetes, gente.
clacke
(Para mayor claridad: cito (como lo dejó en claro la respuesta original, cuando estaba presionando para obtener una cita), y este es un descarrilamiento lateral al que me estoy dirigiendo). Esta afirmación me sorprendió, así que la probé. No es cierto en zsh o bash, pero es cierto en BSD / bin / sh. Esto está en contra de POSIX y es un comportamiento no estándar, por lo que tendrá que cotizar para manejarlo. En zsh, puedes setopt glob_assign para habilitar este comportamiento también, entonces citar es la respuesta más segura.
Phil P