Pregunta

Digamos, usted tiene un alias Bash como:

alias rxvt='urxvt'

que funciona muy bien.

Sin embargo:

alias rxvt='urxvt -fg '#111111' -bg '#111111''

no va a funcionar, y tampoco lo hará:

alias rxvt='urxvt -fg \'#111111\' -bg \'#111111\''

Entonces, ¿cómo se termina haciendo coincidir la apertura y cierre comillas dentro de una cadena una vez que haya escapado cotizaciones?

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''

Parece torpe aunque representaría la misma cadena si se le permite concatenar el estilo.

¿Fue útil?

Solución

Si realmente desea utilizar comillas simples en la capa más externa, recuerde que usted puede pegar los dos tipos de cotización. Ejemplo:

 alias rxvt='urxvt -fg '"'"'#111111'"'"' -bg '"'"'#111111'"'"
 #                     ^^^^^       ^^^^^     ^^^^^       ^^^^
 #                     12345       12345     12345       1234

Explicación de cómo se interpreta como '"'"' simplemente ':

  1. ' extremas primera cita que utiliza comillas simples.
  2. " Comienza segunda cita, el uso de comillas dobles.
  3. ' carácter Citado.
  4. " segundo extremo de la cita, el uso de comillas dobles.
  5. ' Comienza la tercera cita, usando comillas simples.

Si usted no pone ningún espacios en blanco entre (1) y (2), o entre (4) y (5), la cáscara interpretará esa cadena como una palabra larga.

Otros consejos

Siempre basta con sustituir cada una comilla simple incrustada con la secuencia: '\'' (es decir: cita cita cita barra invertida) que cierra la cadena, añade una comilla simple escapado y se vuelve a abrir la cadena.


A menudo preparar una función "quotify" en mis scripts de Perl para hacer esto por mí. Los pasos serían los siguientes:

s/'/'\\''/g    # Handle each embedded quote
$_ = qq['$_']; # Surround result with single quotes.

Esto toma más o menos la atención de todos los casos.

La vida se hace más divertido cuando se introduce eval en su shell-scripts. Esencialmente tiene que volver a quotify todo de nuevo!

Por ejemplo, crear un script Perl llamado quotify que contiene las declaraciones anteriores:

#!/usr/bin/perl -pl
s/'/'\\''/g;
$_ = qq['$_'];

a continuación, utilizarlo para generar una cadena entre comillas correctamente-:

$ quotify
urxvt -fg '#111111' -bg '#111111'

resultado:

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

que luego pueden ser copiar / pegar en el comando alias:

alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

(Si es necesario insertar el comando en un eval, ejecute el quotify nuevo:

 $ quotify
 alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

resultado:

'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

que puede ser copiar / pegar en un eval:

eval 'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

Desde Bash 2,04 $'string' sintaxis (en lugar de sólo 'string'; advertencia: no confundir con $('string')) es otro mecanismo citando que permite secuencias ANSI C-como de escape y hacen expansión a versión entre comillas simples.

Un simple ejemplo:

  $> echo $'aa\'bb'
  aa'bb

  $> alias myvar=$'aa\'bb'
  $> alias myvar
  alias myvar='aa'\''bb'

En su caso:

$> alias rxvt=$'urxvt -fg \'#111111\' -bg \'#111111\''
$> alias rxvt
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

Común escapar secuencias funciona como se espera:

\'     single quote
\"     double quote
\\     backslash
\n     new line
\t     horizontal tab
\r     carriage return

A continuación se muestra la copia + documentación relacionada pegado de man bash (versión 4.4):

Las palabras de la forma $ 'cadena' se tratan de forma especial. La palabra se expande para cuerda, con personajes escapados sustituido como se especifica en la norma ANSI C. secuencias de escape de barra invertida, si están presentes, son decodificados como sigue:

    \a     alert (bell)
    \b     backspace
    \e
    \E     an escape character
    \f     form feed
    \n     new line
    \r     carriage return
    \t     horizontal tab
    \v     vertical tab
    \\     backslash
    \'     single quote
    \"     double quote
    \?     question mark
    \nnn   the eight-bit character whose value is the octal 
           value nnn (one to three digits)
    \xHH   the eight-bit character whose value is the hexadecimal
           value HH (one or two hex digits)
    \uHHHH the Unicode (ISO/IEC 10646) character whose value is 
           the hexadecimal value HHHH (one to four hex digits)
    \UHHHHHHHH the Unicode (ISO/IEC 10646) character whose value 
               is the hexadecimal value HHHHHHHH (one to eight 
               hex digits)
    \cx    a control-x character

El resultado es expandida entre comillas simples, como si el signo del dólar no había estado presente.


Cotizaciones y escapar: ANSI C como cuerdas en Bash-hackers. org wiki para más detalles. También tenga en cuenta que el archivo ( visión general rel="noreferrer"> href="http://wiki.bash-hackers.org/scripting/bashchanges" ) menciona una gran cantidad de cambios y correcciones de errores relacionados con el mecanismo citando $'string'.

Según unix.stackexchange.com Cómo utilizar un carácter especial como uno normal? que debería funcionar (con algunas variaciones) en bash, zsh, mksh, ksh93 y FreeBSD y sh busybox.

No veo la entrada en su blog (enlace pls?) Pero de acuerdo a la gnu manual de referencia :

  

Encerrar caracteres entre comillas simples   ( ‘'’) Conserva el valor literal de   cada personaje dentro de las comillas. UNA   No puede ocurrir entre comilla simple   comillas simples, incluso cuando precedidas por una   barra invertida.

modo fiesta no va a entender:

alias x='y \'z '

Sin embargo, se puede hacer esto si usted se rodea con comillas dobles:

alias x="echo \'y "
> x
> 'y

Puedo confirmar que el uso de '\'' para una comilla simple dentro de una cadena entre comillas simples funciona en Bash, y se puede explicar de la misma manera como el "pegado" argumento del anterior en el hilo. Supongamos que tenemos una cadena entre comillas: 'A '\''B'\'' C' (todas las citas aquí son comillas simples). Si se pasa a hacerse eco, se imprime el siguiente: A 'B' C. En cada '\'' la primera cita se cierra la corriente cadena entre comillas simples, las siguientes colas \' una comilla simple a la cadena anterior (\' es una forma de especificar una comilla simple sin necesidad de iniciar una cadena entre comillas), y la última cita de un solo abre otra cadena entre comillas.

Ejemplo simple de escapar de las cotizaciones en la shell:

$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc

Está hecho de acabado ya abierta una ('), colocando escapado uno (\'), y luego abrir otra ('). Esta sintaxis funciona para todos los comandos. Es enfoque muy similar a la primera respuesta.

Las dos versiones están trabajando, ya sea con la concatenación mediante el carácter de comilla simple escapado (\ '), o con la concatenación encerrando el carácter comilla entre comillas dobles ( "').

El autor de la pregunta no se dio cuenta de que había una cotización individual extra ( ') al final de su último intento de escapar:

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
           │         │┊┊|       │┊┊│     │┊┊│       │┊┊│
           └─STRING──┘┊┊└─STRIN─┘┊┊└─STR─┘┊┊└─STRIN─┘┊┊│
                      ┊┊         ┊┊       ┊┊         ┊┊│
                      ┊┊         ┊┊       ┊┊         ┊┊│
                      └┴─────────┴┴───┰───┴┴─────────┴┘│
                          All escaped single quotes    │
                                                       │
                                                       ?

Como se puede ver en la bonita pieza previa de ASCII / Unicode arte, la última escaparon comilla simple (\ ') está seguida de una comilla simple innecesarias ('). El uso de una sintaxis-resaltador como el que se presente en Notepad ++ puede resultar muy útil.

Lo mismo es cierto para otro ejemplo como la siguiente:

alias rc='sed '"'"':a;N;$!ba;s/\n/, /g'"'"
alias rc='sed '\'':a;N;$!ba;s/\n/, /g'\'

Estas dos hermosas casos de alias muestran de una manera muy compleja y ofuscado cómo un archivo puede ser alineado hacia abajo. Es decir, a partir de un archivo con una gran cantidad de líneas se obtiene una sola línea con comas y espacios entre los contenidos de las líneas anteriores. Con el fin de dar sentido a la observación anterior, la siguiente es un ejemplo:

$ cat Little_Commas.TXT
201737194
201802699
201835214

$ rc Little_Commas.TXT
201737194, 201802699, 201835214

No estoy abordar específicamente el tema citando porque, bueno, a veces, es sólo razonable considerar un enfoque alternativo.

rxvt() { urxvt -fg "#${1:-000000}" -bg "#${2:-FFFFFF}"; }

que luego se puede llamar como:

rxvt 123456 654321

La idea es que ahora se puede alias esto sin preocupación por comillas:

alias rxvt='rxvt 123456 654321'

o, si es necesario incluir la # en todas las llamadas por alguna razón:

rxvt() { urxvt -fg "${1:-#000000}" -bg "${2:-#FFFFFF}"; }

que luego se puede llamar como:

rxvt '#123456' '#654321'

entonces, por supuesto, un alias es:

alias rxvt="rxvt '#123456' '#654321'"

(perdón, supongo que tipo de se refirió a la cita:)

I sólo tiene que utilizar los códigos de carcasa .. por ejemplo \x27 o \\x22 según corresponda. Sin complicaciones, siempre realmente.

Dado que no se puede poner comillas simples dentro de cadenas entre comillas sencillas, la opción más simple y legible es el uso de una cadena heredoc

command=$(cat <<'COMMAND'
urxvt -fg '#111111' -bg '#111111'
COMMAND
)

alias rxvt=$command

En el código anterior, la heredoc se envía al comando cat y se le asigna la salida de ese a una variable a través de la $(..) notación sustitución de orden

Poner una comilla simple en todo el heredoc es necesaria ya que está dentro de un $()

En mi humilde opinión la verdadera respuesta es que no se puede escapar comillas simples dentro de cadenas entre comillas simples.

Es imposible.

Si suponemos que estamos utilizando bash.

A partir de manual de fiesta ...

Enclosing characters in single quotes preserves the literal value of each
character within the quotes.  A single quote may not occur
between single quotes, even when preceded by a backslash.

Es necesario utilizar uno de los otros mecanismos de escape de cadena "o \

No hay nada mágico sobre alias que exige utilizar comillas simples.

Tanto los siguientes trabajos en bash.

alias rxvt="urxvt -fg '#111111' -bg '#111111'"
alias rxvt=urxvt\ -fg\ \'#111111\'\ -bg\ \'#111111\'

Este último está utilizando \ escapar el carácter de espacio.

También hay nada mágico sobre # 111111 que requiere comillas simples.

Las siguientes opciones se consigue el mismo resultado las otras dos opciones, en la que funciona el alias rxvt como se esperaba.

alias rxvt='urxvt -fg "#111111" -bg "#111111"'
alias rxvt="urxvt -fg \"#111111\" -bg \"#111111\""

También puede escapar de la problemática directamente #

alias rxvt="urxvt -fg \#111111 -bg \#111111"

La mayoría de estas respuestas golpeado en el caso concreto que estés preguntando por. Hay un enfoque general que un amigo y yo hemos desarrollado que permite arbitraria citar en caso de tener que citar a los comandos de bash a través de múltiples capas de desarrollo del forro, por ejemplo, a través de ssh, su -c, bash -c, etc. Hay un núcleo primitivo que necesita , aquí en bash orígenes:

quote_args() {
    local sq="'"
    local dq='"'
    local space=""
    local arg
    for arg; do
        echo -n "$space'${arg//$sq/$sq$dq$sq$dq$sq}'"
        space=" "
    done
}

Esto hace exactamente lo que dice: TI-shell cotizaciones de cada uno de los argumentos individualmente (después de la expansión fiesta, por supuesto):

$ quote_args foo bar
'foo' 'bar'
$ quote_args arg1 'arg2 arg2a' arg3
'arg1' 'arg2 arg2a' 'arg3'
$ quote_args dq'"'
'dq"'
$ quote_args dq'"' sq"'"
'dq"' 'sq'"'"''
$ quote_args "*"
'*'
$ quote_args /b*
'/bin' '/boot'

Se hace lo obvio para una capa de expansión:

$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2

(Tenga en cuenta que las comillas dobles $(quote_args ...) son necesarias para que el resultado en un solo argumento a bash -c.) Y puede ser utilizado de manera más general para citar correctamente a través de múltiples capas de expansión:

$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2

El ejemplo anterior:

  1. shell-citas cada argumento a la quote_args interior individual y luego combina la salida resultante en un solo argumento con las comillas dobles internos.
  2. shell-citas bash, -c, y el resultado ya citado una vez desde el paso 1, y después se combina el resultado en un único argumento con las comillas dobles exteriores.
  3. envía ese lío como el argumento de la bash -c exterior.

Esa es la idea en pocas palabras. Usted puede hacer algunas cosas bastante complicado con este, pero hay que tener cuidado con la orden de evaluación y sobre los cuales se citan subcadenas. Por ejemplo, la siguiente hacer las cosas mal (por alguna definición de "malo"):

$ (cd /tmp; bash -c "$(quote_args cd /; pwd 1>&2)")
/tmp
$ (cd /tmp; bash -c "$(quote_args cd /; [ -e *sbin ] && echo success 1>&2 || echo failure 1>&2)")
failure

En el primer ejemplo, golpe expande inmediatamente quote_args cd /; pwd 1>&2 en dos comandos separados, quote_args cd / y pwd 1>&2, por lo que el CWD es todavía /tmp cuando se ejecuta el comando pwd. El segundo ejemplo ilustra un problema similar para globbing. De hecho, el mismo problema básico ocurre con todas las expansiones de bash. El problema aquí es que una sustitución de orden no es una llamada a la función:. Es, literalmente, una evaluación de escritura del golpe y el uso de su producción como parte de otro script bash

Si intenta simplemente escapar de los operadores de concha, usted fallará debido a que la cadena resultante pasó a bash -c es sólo una secuencia de cadenas entre comillas individual que no son interpretados como operadores, que es fácil de ver si repites la cadena que se habría pasado a bash:

$ (cd /tmp; echo "$(quote_args cd /\; pwd 1\>\&2)")
'cd' '/;' 'pwd' '1>&2'
$ (cd /tmp; echo "$(quote_args cd /\; \[ -e \*sbin \] \&\& echo success 1\>\&2 \|\| echo failure 1\>\&2)")
'cd' '/;' '[' '-e' '*sbin' ']' '&&' 'echo' 'success' '1>&2' '||' 'echo' 'failure' '1>&2'

El problema aquí es que eres un exceso de citar. Lo que necesita es que los operadores pueden no cotizados como entrada a la bash -c envolvente, lo que significa que tienen que estar fuera de la sustitución de comandos $(quote_args ...).

Por lo tanto, lo que hay que hacer en el sentido más general es sin cáscara cita cada palabra del comando no destinada a ser ampliado en el momento de la sustitución de comandos por separado, y no aplicar ningún extra citando a los operadores de concha:

$ (cd /tmp; echo "$(quote_args cd /); $(quote_args pwd) 1>&2")
'cd' '/'; 'pwd' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")
/
$ (cd /tmp; echo "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
'cd' '/'; [ -e *'sbin' ] && 'echo' 'success' 1>&2 || 'echo' 'failure' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
success

Una vez hecho esto, la cadena entera es un juego justo por citar aún más a niveles arbitrarios de evaluación:

$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")"
/
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")"
/
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")")"
/
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")"
success
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *sbin ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")"
success
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")")"
success

etc.

Estos ejemplos pueden parecer sobreexcitada dado que palabras como success, sbin y pwd no necesitan ser cáscara citado, pero el punto clave a recordar al escribir un guión teniendo entrada arbitraria es que desea citar todo lo que' re no absolutamente seguro de no ¿necesita citar, porque nunca se sabe cuando un usuario va a lanzar en un Robert'; rm -rf /.

Para entender mejor lo que está pasando debajo de las mantas, se puede jugar con dos funciones de ayuda pequeñas:

debug_args() {
    for (( I=1; $I <= $#; I++ )); do
        echo -n "$I:<${!I}> " 1>&2
    done
    echo 1>&2
}

debug_args_and_run() {
    debug_args "$@"
    "$@"
}

que va a enumerar cada argumento a un comando antes de ejecutarlo:

$ debug_args_and_run echo a'"'b"'"c arg2
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)"
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''> 
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'bash'"'"' '"'"'-c'"'"' '"'"''"'"'"'"'"'"'"'"'debug_args_and_run'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'echo'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'a"b'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'c'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'arg2'"'"'"'"'"'"'"'"''"'"''> 
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''> 
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'> 
1:<echo> 2:<a"b'c> 3:<arg2> 
a"b'c arg2

En el ejemplo dado, simplemente utiliza comillas dobles en lugar de comillas simples como mecanismo de escape exterior:

alias rxvt="urxvt -fg '#111111' -bg '#111111'"

Este enfoque es adecuado para muchos casos en los que sólo quieren pasar una cadena fija a un comando:. Sólo comprobar cómo la cáscara interpretará la cadena entre comillas dobles a través de un echo y caracteres de escape con barra invertida si es necesario

En el ejemplo, vería que las comillas dobles son suficientes para proteger la cadena:

$ echo "urxvt -fg '#111111' -bg '#111111'"
urxvt -fg '#111111' -bg '#111111'

Este es un Elaboración Por una verdadera respuesta referencia anteriormente:

A veces Descargaré usando rsync sobre ssh y tienen que escapar de un nombre de archivo con un "en ella dos veces! (OMG!) Una vez para bash y una vez por ssh. El mismo principio de alternancia delimitadores cita es en el trabajo aquí.

Por ejemplo, supongamos que queremos llegar: LA Historias de Louis Theroux ...

  1. En primer lugar se encierra Louis Theroux entre comillas simples para bash y comillas dobles para ssh: 'Louis Theroux "'
  2. A continuación, utilice comillas simples para escapar de las comillas '"'
  3. El uso de comillas dobles para escapar el apóstrofe "'"
  4. A continuación, repita # 2, usando comillas simples para escapar de las comillas '"'
  5. Luego encierre LA Historias en comillas simples para bash y comillas dobles para ssh: 'LA Historias "'

Y he aquí! Como resultado, terminamos con esto:

rsync -ave ssh '"Louis Theroux"''"'"'"'"''"s LA Stories"'

que es un montón de trabajo por un pequeño '- pero hay que ir

Otra forma de solucionar el problema de demasiadas capas de cita anidada:

Usted está tratando de meter demasiado en demasiado pequeño un espacio, a fin de utilizar una función bash.

El problema es que está tratando de tener demasiados niveles de anidación, y la tecnología básica alias no es lo suficientemente potente como para dar cabida. Utilizar una función como esta fiesta para que sea lo que los simples, comillas dobles copias de las garrapatas y se pasa en los parámetros se manejan normalmente como era de esperar:

lets_do_some_stuff() {
    tmp=$1                       #keep a passed in parameter.
    run_your_program $@          #use all your passed parameters.
    echo -e '\n-------------'    #use your single quotes.
    echo `date`                  #use your back ticks.
    echo -e "\n-------------"    #use your double quotes.
}
alias foobarbaz=lets_do_some_stuff

A continuación, puede utilizar las variables $ 1 y $ 2 y, comillas dobles individuales y vuelta garrapatas sin tener que preocuparse acerca de la función de alias destruyendo su integridad.

Este programa imprime:

el@defiant ~/code $ foobarbaz alien Dyson ring detected @grid 10385
alien Dyson ring detected @grid 10385
-------------
Mon Oct 26 20:30:14 EDT 2015
-------------
shell_escape () {
    printf '%s' "'${1//\'/\'\\\'\'}'"
}

Implementación explicación:

  • comillas dobles para que podamos envolver fácilmente salida comillas simples y usan la sintaxis ${...}

  • Búsqueda de fiesta y vuelva a colocar el siguiente aspecto: ${varname//search/replacement}

  • estamos reemplazando con ' '\''

  • '\'' codifica una sola ' así:

    1. termina ' la única citando

    2. \' codifica una ' (se necesita la barra invertida porque estamos cotizaciones no dentro)

    3. ' inicia solo citando de nuevo

    4. golpe concatena automáticamente cadenas con ningún espacio en blanco entre

  • hay un \ antes de cada \ y ' porque eso es las reglas de escape para ${...//.../...}.

string="That's "'#@$*&^`(@#'
echo "original: $string"
echo "encoded:  $(shell_escape "$string")"
echo "expanded: $(bash -c "echo $(shell_escape "$string")")"

P.S. Siempre codificar singularizar cadenas entre comillas, ya que son la forma más simple que las cadenas entre comillas dobles.

Si ha instalado GNU paralelo puede utilizar su interior citar:

$ parallel --shellquote
L's 12" record
<Ctrl-D>
'L'"'"'s 12" record'
$ echo 'L'"'"'s 12" record'
L's 12" record

A partir de la versión 20190222 incluso se puede --shellquote varias veces:

$ parallel --shellquote --shellquote --shellquote
L's 12" record
<Ctrl-D>
'"'"'"'"'"'"'L'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'s 12" record'"'"'"'"'"'"'
$ eval eval echo '"'"'"'"'"'"'L'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'s 12" record'"'"'"'"'"'"'
L's 12" record

Se citará la cadena en todas las conchas compatibles (no sólo bash).

Esta función:

quote () 
{ 
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

permite citando de ' dentro '. Utilizar como esto:

$ quote "urxvt -fg '#111111' -bg '#111111'"
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

Si la línea de cotización se vuelve más complejo, como comillas dobles mezclados con comillas simples, puede llegar a ser bastante difícil de obtener la cadena de citar el interior de una variable. Cuando estos casos se presenta, escribir la línea exacta que usted necesita cotizar dentro de una secuencia de comandos (similar a éste).

#!/bin/bash

quote ()
{
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

while read line; do
    quote "$line"
done <<-\_lines_to_quote_
urxvt -fg '#111111' -bg '#111111'
Louis Theroux's LA Stories
'single quote phrase' "double quote phrase"
_lines_to_quote_

salida será:

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
'Louis Theroux'\''s LA Stories'
''\''single quote phrase'\'' "double quote phrase"'

Todas las cadenas correctamente citadas entre comillas simples.

Obviamente, sería más fácil simplemente para rodear con comillas dobles, pero ¿dónde está el desafío en eso? Aquí está la respuesta utilizando cotizaciones sólo individuales. Estoy usando una variable en lugar de alias por lo que es que es más fácil de imprimir una prueba, pero es lo mismo que usar alias.

$ rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'
$ echo $rxvt
urxvt -fg '#111111' -bg '#111111'

Explicación

La clave es que se puede cerrar la comilla simple y volver a abrir tantas veces como desee. Por ejemplo foo='a''b' es el mismo que foo='ab'. Para que pueda cerrar la comilla simple, lanzar en un \' comilla simple literal, vuelva a abrir la siguiente comilla simple.

diagrama Desglose

Este diagrama pone de manifiesto mediante el uso de soportes para mostrar dónde se abren las comillas simples y cerradas. Cotizaciones no están "anidados", como pueden ser paréntesis. También puede prestar atención al color de resaltado, que se aplica correctamente. Las cadenas entre comillas son de color marrón, mientras que el \' es negro.

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'    # original
[^^^^^^^^^^] ^[^^^^^^^] ^[^^^^^] ^[^^^^^^^] ^    # show open/close quotes
 urxvt -fg   ' #111111  '  -bg   ' #111111  '    # literal characters remaining

(Esta es esencialmente la misma respuesta que Adrian, pero me siento esto explica mejor. También su respuesta tiene 2 comillas simples superfluos al final.)

Aquí hay otra solución. Esta función se llevará a un solo argumento y apropiadamente citarlo mediante el carácter de una sola cita, al igual que la respuesta votado anterior explica:

single_quote() {
  local quoted="'"
  local i=0
  while [ $i -lt ${#1} ]; do
    local ch="${1:i:1}"
    if [[ "$ch" != "'" ]]; then
      quoted="$quoted$ch"
    else
      local single_quotes="'"
      local j=1
      while [ $j -lt ${#1} ] && [[ "${1:i+j:1}" == "'" ]]; do
        single_quotes="$single_quotes'"
        ((j++))
      done
      quoted="$quoted'\"$single_quotes\"'"
      ((i+=j-1))
    fi
    ((i++))
  done
  echo "$quoted'"
}

Por lo tanto, se puede utilizar de esta manera:

single_quote "1 2 '3'"
'1 2 '"'"'3'"'"''

x="this text is quoted: 'hello'"
eval "echo $(single_quote "$x")"
this text is quoted: 'hello'

Si se está generando la cáscara de la secuencia dentro de Python 2 o Python 3, lo siguiente puede ayudar a citar los argumentos:

#!/usr/bin/env python

from __future__ import print_function

try:  # py3
    from shlex import quote as shlex_quote
except ImportError:  # py2
    from pipes import quote as shlex_quote

s = """foo ain't "bad" so there!"""

print(s)
print(" ".join([shlex_quote(t) for t in s.split()]))

Esta es la salida:

foo ain't "bad" so there!
foo 'ain'"'"'t' '"bad"' so 'there!'
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top