¿Cómo escapar de las comillas simples dentro de las cadenas citadas?

Digamos que tienes un alias bash como:

 alias rxvt='urxvt' 

que funciona bien

Sin embargo:

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

no funcionará, y tampoco lo hará:

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

Entonces, ¿cómo terminas haciendo coincidir las comillas de apertura y cierre dentro de una cadena una vez que has escapado de las comillas?

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

parece desgarbado, aunque representaría la misma cadena si se le permite concatenarlos así.

Si realmente desea utilizar comillas simples en la capa más externa, recuerde que puede pegar ambos tipos de citas. Ejemplo:

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

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

  1. ' Fin primera cita que utiliza comillas simples.
  2. " Comience la segunda cita, usando comillas dobles.
  3. ' Citado personaje.
  4. " Fin segunda cita, usando comillas dobles.
  5. ' Comience la tercera cita, usando comillas simples.

Si no coloca espacios en blanco entre (1) y (2), o entre (4) y (5), el intérprete interpretará esa cadena como una palabra larga.

Siempre reemplazo simplemente cada comilla simple incrustada con la secuencia: '\'' (es decir: quote quote quote quote) que cierra la cadena, agrega una comilla simple escapada y vuelve a abrir la cadena.


A menudo hago funcionar una función “quotify” en mis scripts de Perl para hacer esto por mí. Los pasos serían:

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

Esto prácticamente se ocupa de todos los casos.

La vida se vuelve más divertida cuando introduces eval en tus scripts de shell. ¡Esencialmente tienes que volver a calcular todo de nuevo!

Por ejemplo, crea un script de Perl llamado quotify que contenga las declaraciones anteriores:

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

luego utilícelo para generar una cadena citada correctamente:

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

resultado:

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

que luego puede copiarse / pegarse en el comando alias:

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

(Si necesita insertar el comando en un eval, ejecute el comando quotify nuevamente:

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

resultado:

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

que se puede copiar / pegar en una evaluación:

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

Desde Bash 2.04 syntax $'string' (en lugar de solo 'string' ; advertencia: no confunda con $('string') ) es otro mecanismo de cita que permite secuencias de escape ANSI tipo C y hace la expansión a la versión de una sola cita.

Ejemplo simple:

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

En tu caso:

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

Las secuencias de escape comunes funcionan como se esperaba:

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

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

Las palabras de la forma $ ‘cadena’ se tratan especialmente. La palabra se expande a cadena, con caracteres de barra invertida escapados como se especifica en el estándar ANSI C. Las secuencias de escape de barra invertida, si están presentes, se decodifican de la siguiente manera:

  \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 ampliado se cita por separado, como si el signo de dólar no hubiera estado presente.


Vea Citas y escape: ANSI C, como cadenas en la wiki de bash-hackers.org para más detalles. También tenga en cuenta que el archivo “Bash Changes” ( descripción general aquí ) menciona mucho los cambios y las correcciones de errores relacionados con el mecanismo de cotización $'string' .

De acuerdo con unix.stackexchange.com ¿Cómo usar un personaje especial como uno normal? debería funcionar (con algunas variaciones) en bash, zsh, mksh, ksh93 y FreeBSD y busybox sh.

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

El incluir caracteres en comillas simples (” ‘) conserva el valor literal de cada carácter dentro de las comillas. Es posible que una comilla simple no se produzca entre comillas simples, incluso cuando esté precedida por una barra diagonal inversa.

así que bash no entenderá:

alias x='y \'z '

sin embargo, puedes hacer esto si rodeas con comillas dobles:

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

Puedo confirmar que el uso de '\'' para una comilla simple dentro de una cadena de una sola cita funciona en Bash, y se puede explicar de la misma manera que el argumento “pegado” de la primera parte del hilo. Supongamos que tenemos una cadena entre comillas: 'A '\''B'\'' C' (todas las comillas aquí son comillas simples). Si se pasa a eco, imprime lo siguiente: A 'B' C En cada '\'' la primera cita cierra la cadena actual entre comillas simples, la siguiente \' pega una comilla simple a la cadena anterior ( \' es una forma de especificar una comilla simple sin iniciar una cadena entre comillas), y la última quote abre otra cadena de una sola cita.

Ejemplo simple de escaping quotes in shell:

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

Se hace terminando uno ya abierto ( ' ), colocando uno escapado ( \' ), luego abriendo otro ( ' ). Esta syntax funciona para todos los comandos. Es un enfoque muy similar a la primera respuesta.

No estoy abordando específicamente el tema de las citas porque, bueno, a veces, es razonable considerar un enfoque alternativo.

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

que puedes llamar como:

 rxvt 123456 654321 

la idea es que ahora puede alias esto sin preocuparse por las comillas:

 alias rxvt='rxvt 123456 654321' 

o, si necesita incluir el # en todas las llamadas por algún motivo:

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

que puedes llamar como:

 rxvt '#123456' '#654321' 

entonces, por supuesto, un alias es:

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

(Ups, supongo que me dirigí a las citas 🙂

Solo uso códigos de shell … por ejemplo, \x27 o \\x22 según corresponda. Sin problemas, nunca realmente.

Como no se pueden poner comillas simples dentro de las cadenas entre comillas simples, la opción más simple y más fácil de leer es usar una cadena HEREDOC.

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

En el código anterior, el HEREDOC se envía al comando cat y el resultado de eso se asigna a una variable mediante el comando sustitución de notación $(..)

Es necesario poner una sola cotización alrededor de HEREDOC ya que está dentro de un $()

Ambas versiones funcionan, ya sea con concatenación mediante el uso del carácter de comillas simples escapado (\ ‘), o con concatenación al encerrar el carácter de comillas simples entre comillas dobles (“‘”).

El autor de la pregunta no se dio cuenta de que había una comilla simple adicional (‘) al final de su último bash de fuga:

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

Como puede ver en la buena pieza anterior de arte ASCII / Unicode, la última comilla simple escapada (\ ‘) va seguida de una comilla simple innecesaria (‘). Usar un marcador de syntax como el presente en Notepad ++ puede ser muy útil.

Lo mismo es cierto para otro ejemplo como el siguiente:

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

Estas dos hermosas instancias de alias muestran de una manera muy intrincada y confusa cómo se puede alinear un archivo. Es decir, de un archivo con muchas líneas solo se obtiene una línea con comas y espacios entre los contenidos de las líneas anteriores. Para dar sentido al comentario anterior, el siguiente es un ejemplo:

 $ cat Little_Commas.TXT 201737194 201802699 201835214 $ rc Little_Commas.TXT 201737194, 201802699, 201835214 

La mayoría de estas respuestas afectan al caso específico sobre el que preguntas. Hay un enfoque general que un amigo y yo hemos desarrollado que permite citas arbitrarias en caso de que necesite citar comandos de bash a través de múltiples capas de expansión de shell, por ejemplo, a través de ssh, su -c , bash -c , etc. Hay uno núcleo primitivo que necesitas, aquí en bash nativo:

 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: contrae cada argumento individualmente (después de la expansión de bash, 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' 

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 alrededor de $(quote_args ...) son necesarias para convertir el resultado en un único argumento para bash -c ). Y se puede usar de manera más general para citar correctamente a través de varias capas de expansión:

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

El ejemplo de arriba:

  1. shell-quotes cada argumento a la quote_args interna individualmente y luego combina la salida resultante en un solo argumento con las comillas dobles interiores.
  2. shell-quotes bash , -c , y el resultado que ya se citó una vez en el paso 1, y luego combina el resultado en un único argumento con las comillas dobles externas.
  3. envía ese lío como el argumento al exterior bash -c .

Esa es la idea en pocas palabras. Puede hacer algunas cosas bastante complicadas con esto, pero debe tener cuidado con el orden de evaluación y sobre las subcadenas que se citan. Por ejemplo, los siguientes hacen las cosas incorrectas (para alguna definición de “incorrecto”):

 $ (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, bash expande inmediatamente quote_args cd /; pwd 1>&2 quote_args cd /; pwd 1>&2 en dos comandos separados, quote_args cd / y pwd 1>&2 , por lo que el CWD sigue siendo /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 comando no es una llamada a función: está literalmente evaluando un script bash y usando su salida como parte de otro script bash.

Si intenta simplemente escapar de los operadores de shell, fallará porque la cadena resultante transferida a bash -c es solo una secuencia de cadenas entre comillas individuales que no se interpretan entonces como operadores, lo que es fácil de ver si hace eco del cadena que se hubiera 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 estás sobre-cotizando. Lo que necesita es que los operadores no sean cotejados como entrada para el bash -c que los encierra, lo que significa que deben estar fuera de la sustitución del comando $(quote_args ...) .

En consecuencia, lo que debe hacer en el sentido más general es citar con shell cada palabra del comando que no se pretende expandir en el momento de la sustitución del comando por separado, y no aplicar ninguna cotización adicional a los operadores de shell:

 $ (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 que haya hecho esto, toda la cadena es un juego justo para cotizaciones adicionales 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 exagerados dado que palabras como success , sbin y pwd no necesitan ser citadas con shell, pero el punto clave a recordar cuando se escribe un script que toma una entrada arbitraria es que se quiere citar todo lo que no se es absolutamente seguro que no necesita cotizaciones, porque nunca se sabe cuándo un usuario arrojará un Robert'; rm -rf / Robert'; rm -rf / .

Para comprender mejor lo que sucede bajo las sábanas, puedes jugar con dos pequeñas funciones de ayuda:

 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 enumerará cada argumento a un comando antes de ejecutarlo:

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

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

Es imposible.

Si suponemos que estamos usando bash.

Desde el manual bash …

 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. 

Necesita usar uno de los otros mecanismos de escape de cadenas “o \

No hay nada mágico acerca de alias que exija el uso de comillas simples.

Ambos el siguiente trabajo en bash.

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

Este último está usando \ para escapar del carácter de espacio.

Tampoco hay nada de mágico sobre # 111111 que requiera comillas simples.

Las siguientes opciones logran el mismo resultado que las otras dos opciones, ya que el alias rxvt funciona como se esperaba.

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

También puedes escapar del problemático # directamente

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

En el ejemplo dado, simplemente usó comillas dobles en lugar de comillas simples como mecanismo de escape externo:

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

Este enfoque es adecuado para muchos casos en los que solo desea pasar una cadena fija a un comando: simplemente verifique cómo el intérprete interpretará la secuencia de comillas dobles a través de un echo y escapará caracteres con barra invertida si es necesario.

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

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

Aquí hay una explicación sobre The One True Answer mencionada anteriormente:

A veces voy a descargar usando rsync sobre ssh y tengo que escapar de un nombre de archivo con un ‘¡DOS VECES! (¡Dios mío!) Una vez para bash y una vez para ssh. El mismo principio de delimitadores de comillas alternados funciona aquí.

Por ejemplo, digamos que queremos obtener: Historias de Luis Theroux en LA …

  1. Primero encierran a Louis Theroux en comillas simples para bash y comillas dobles para ssh: “Louis Theroux”
  2. Luego usas comillas simples para escapar de una comilla doble ” ”
  3. El uso de comillas dobles para escapar del apóstrofo “‘”
  4. Luego repite # 2, usando comillas simples para escapar de una comilla doble ” ”
  5. Luego encierre LA Stories entre comillas simples para bash y comillas dobles para ssh: ‘”LA Stories”‘

Y he aquí! Terminas con esto:

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

que es un montón de trabajo para un poco ‘- pero ahí lo tienes

Otra forma de solucionar el problema de demasiadas capas de presupuestos nesteds:

Estás tratando de meter demasiado en un espacio demasiado pequeño, así que usa una función bash.

El problema es que está tratando de tener demasiados niveles de anidación, y la tecnología básica de alias no es lo suficientemente poderosa como para acomodarse. Use una función bash como esta para que las comillas sencillas, dobles y las pasadas en parámetros se manejen normalmente como cabría 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 

Luego puede usar sus variables de $ 1 y $ 2 y comillas simples, dobles y regresivas sin preocuparse de que la función de alias arruine su integridad.

Este progtwig 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 ------------- 

Esta función:

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

permite citar ' adentro ' . Use como esto:

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

Si la línea que se va a citar se vuelve más compleja, como las comillas dobles mezcladas con comillas simples, puede ser bastante complicado hacer que la cadena cite dentro de una variable. Cuando se presenten tales casos, escriba la línea exacta que necesita para citar dentro de una secuencia de comandos (similar a esto).

 #!/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_ 

Se producirá:

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

Todas las cadenas correctamente citadas dentro de comillas simples.

Obviamente, sería más fácil simplemente rodear con comillas dobles, pero ¿cuál es el desafío en eso? Aquí está la respuesta usando solo comillas simples. Estoy usando una variable en lugar de un alias así que es más fácil imprimir para obtener pruebas, 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 puede cerrar la comilla simple y volver a abrirla tantas veces como desee. Por ejemplo, foo='a''b' es lo mismo que foo='ab' . De modo que puede cerrar la comilla simple, incluir una comilla simple literal \' y luego volver a abrir la siguiente comilla simple.

Diagtwig de desglose

Este diagtwig lo aclara al usar corchetes para mostrar dónde se abren y cierran las comillas simples. Las citas no están “anidadas” como los paréntesis pueden ser. También puede prestar atención al resaltado de color, que se aplica correctamente. Las cadenas citadas son granate, 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 la de Adrian, pero creo que esto lo explica mejor. También su respuesta tiene 2 comillas simples superfluas al final).

Aquí hay otra solución. Esta función tomará un solo argumento y lo citará apropiadamente usando el carácter de comillas simples, tal como lo explica la respuesta anterior:

 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'" } 

Entonces, puedes usarlo 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 está generando la cadena de shell 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()])) 

Esto dará como resultado:

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