¿Por qué echo ignora mis caracteres de cita?


24

El echocomando no incluye el texto completo que le doy. Por ejemplo, si lo hago:

   $ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '

Produce:

echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print } `

Las comillas simples ( ') que tenía en mi comando echo no están incluidas. Si cambio a comillas dobles:

$ echo " echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `  "

echo¡no produce nada en absoluto! ¿Por qué deja de lado las comillas simples en el primer ejemplo y no muestra nada en el segundo? ¿Cómo consigo que emita exactamente lo que escribí?


3
No estoy seguro de lo que estás tratando de lograr aquí. ¿Por qué anidas una declaración de eco en otra? ¿O está literalmente tratando de imprimir un comando (por ejemplo o similar)?
Andy Smith

Necesito insertar la salida de eco en otro archivo

Necesitas explicar lo que estás tratando de hacer. Como "Quiero agregar el siguiente texto: '...' a un archivo".
MikeyB

2
He estado tratando de editar esto durante 5 minutos, pero realmente no sé cuál es el resultado deseado. Editar : Ok, creo que tengo una suposición ahora, así que intenté editar. Si no es lo que pretendías, házmelo saber
Michael Mrozek

1
@Michael - Wow - Si pudiera darte un representante para tu edición, lo haría - ¡buen trabajo haciendo de esta una gran pregunta!
Randall

Respuestas:


33

Su shell está interpretando las citas, ambas 'y ", incluso antes de que lleguen echo. Generalmente pongo comillas dobles alrededor de mi argumento para hacer eco, incluso si son innecesarias; por ejemplo:

$ echo "Hello world"
Hello world

Entonces, en su primer ejemplo, si desea incluir comillas literales en su salida, es necesario que escapen:

$ echo \'Hello world\'
'Hello world'

O ya deben usarse dentro de un argumento citado (pero no puede ser el mismo tipo de cita, o tendrá que escapar de todos modos):

$ echo "'Hello world'"
'Hello world'

$ echo '"Hello world"'
"Hello world"

En su segundo ejemplo, está ejecutando una sustitución de comando en el medio de la cadena:

grep  $ARG  /var/tmp/setfile  | awk {print $2}

Las cosas que comienzan $también se manejan especialmente por el shell: las trata como variables y las reemplaza por sus valores. Como lo más probable es que ninguna de esas variables esté configurada en su shell, en realidad solo se ejecuta

grep /var/tmp/setfile | awk {print}

Como grepsolo ve un argumento, asume que ese argumento es el patrón que está buscando, y que el lugar desde el que debe leer los datos es stdin, por lo que bloquea la espera de entrada. Es por eso que su segundo comando parece simplemente colgarse.

Esto no sucederá si cita el argumento con comillas simples (es por eso que su primer ejemplo casi funcionó), por lo que esta es una forma de obtener el resultado que desea:

echo \'' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '\'

También puede ponerlo entre comillas dobles, pero luego necesitará escapar de la $s para que el shell no los resuelva como variables, y los backticks para que el shell no ejecute la sustitución del comando de inmediato:

echo "' echo PARAM=\`  grep  \$ARG  /var/tmp/setfile  | awk '{print \$2}' \`    '"

7

No voy a entrar en muchos detalles sobre por qué sus intentos se comportan de la manera en que lo hacen, porque la respuesta de Michael Mrozek cubre esto bien. En pocas palabras, todo lo que entre comillas simples ( '…') se interpreta literalmente (y en particular, la primera 'marca el final de la cadena literal), mientras que `y $conservan su significado especial entre "…".

No hay comillas dentro de comillas simples, por lo que no puede poner una comilla simple dentro de una cadena entre comillas simples. Sin embargo, hay un idioma que se ve así:

echo 'foo'\''bar'

Esto se imprime foo'bar, porque el argumento de echoestá hecho de la cadena de tres caracteres entre comillas simples foo, concatenado con el carácter único '(obtenido al proteger el carácter 'de su significado especial a través del precedente \), concatenado con la cadena de tres caracteres entre comillas simples bar. Entonces, aunque eso no es exactamente lo que sucede detrás de escena, se puede considerar '\''como una forma de incluir una comilla simple dentro de una cadena entre comillas simples.

Si desea imprimir cadenas complejas de varias líneas, una mejor herramienta es el documento aquí . Un documento aquí consta de los dos caracteres <<seguidos de un marcador como <<EOF, luego, algunas líneas de texto, luego el marcador final solo en su línea. Si el marcador se cita de alguna manera ( 'EOF'oo "EOF"o \EOF'E "" OF' o ...), entonces el texto se interpreta literalmente (como dentro de comillas simples, excepto que incluso 'es un carácter ordinario). Si el marcador no se cita en absoluto, entonces el texto se interpreta como una cadena entre comillas dobles, $\`conservando su estado especial (pero las "líneas nuevas se interpretan literalmente).

cat <<'EOF'
echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `
EOF

1

De acuerdo, esto funcionará: -

echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '

Probándolo aquí: -

[asmith@yagi ~]$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '
 echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' ` 

0

La sugerencia de Gilles de usar un documento aquí es realmente agradable, e incluso funciona dentro de lenguajes de script como Perl. Como un ejemplo específico basado en su respuesta al problema del OP,

use strict;
my $cmd = q#cat <<'EOF' # . "\n" .
          q#echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `# . "\n" .
          q#EOF# ;
open (my $OUTPUT, "$cmd |");
print $_ while <$OUTPUT>;
close $OUTPUT;

Por supuesto, este ejemplo es un poco artificial, pero he encontrado que es una técnica útil para, por ejemplo, enviar sentencias SQL a psql(en lugar de cat).

(Tenga en cuenta que cualquier carácter no alfanumérico que no sea un espacio se puede usar en lugar de la #construcción de citas genéricas anterior, pero el hash parece destacarse bien para este ejemplo, y no se trata como un comentario).


-1

Tomemos tu comando

$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '

y primero se divide en palabras, usando espacios en blanco sin comillas como delimitador:

Arg[1]=“' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print”
Arg[2]=“$2}' `    '”

A continuación, hacemos la expansión de parámetros: expandir $…pero no dentro '…'. Como $2está vacío (a menos que lo establezca a través de, p set -- …. Ej. ), Será reemplazado por una cadena vacía.

Arg[1]=“' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print”
Arg[2]=“}' `    '”

Luego, elimine las cotizaciones.

Arg[1]=“ echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print”
Arg[2]=“} `    ”

Estos argumentos se pasan a echo, que los imprimirá uno tras otro, separados por un solo espacio.

“ echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print } `    ”

Espero que esta instrucción paso a paso aclare el comportamiento observado. Para evitar el problema, evite las comillas simples como esta:

$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '

Esto finalizará la cadena de comillas simples, luego agregará una comilla simple (escapado) a la palabra, luego comenzará una nueva cadena de comillas simples, todo sin separar la palabra.

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.