it-swarm.com.de

Warum ignoriert Echo meine Anführungszeichen?

Der Befehl echo enthält nicht den vollständigen Text, den ich ihm gebe. Zum Beispiel, wenn ich:

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

Es gibt aus:

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

Die einfachen Anführungszeichen (') Ich hatte in meinem Echo-Befehl nicht enthalten. Wenn ich zu doppelten Anführungszeichen wechsle:

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

echo gibt überhaupt nichts aus! Warum werden im ersten Beispiel die einfachen Anführungszeichen weggelassen und im zweiten nichts ausgegeben? Wie kann ich genau das ausgeben, was ich eingegeben habe?

24
Diana

Ihre Shell interpretiert die Anführungszeichen ' Und ", Bevor sie überhaupt zu echo gelangen. Im Allgemeinen setze ich meine Argumentation nur in doppelte Anführungszeichen, um sie wiederzugeben, auch wenn sie nicht erforderlich sind. zum Beispiel:

$ echo "Hello world"
Hello world

Wenn Sie also in Ihrem ersten Beispiel wörtliche Anführungszeichen in Ihre Ausgabe aufnehmen möchten, müssen diese entweder maskiert werden:

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

Oder sie müssen bereits in einem zitierten Argument verwendet werden (aber es kann nicht dieselbe Art von Zitat sein, oder Sie müssen es trotzdem umgehen):

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

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

In Ihrem zweiten Beispiel führen Sie eine Befehlsersetzung in der Mitte der Zeichenfolge aus:

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

Dinge, die mit $ Beginnen, werden auch speziell von der Shell behandelt - sie behandelt sie als Variablen und ersetzt sie durch ihre Werte. Da höchstwahrscheinlich keine dieser Variablen in Ihrer Shell festgelegt ist, wird sie tatsächlich nur ausgeführt

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

Da grep nur ein Argument sieht, wird davon ausgegangen, dass das Argument das gesuchte Muster ist und dass der Ort, von dem Daten gelesen werden sollen, stdin ist, sodass das Warten auf Eingabe blockiert wird. Deshalb scheint Ihr zweiter Befehl nur zu hängen.

Dies ist nicht der Fall, wenn Sie das Argument in einfache Anführungszeichen setzen (weshalb Ihr erstes Beispiel fast funktioniert hat). Dies ist also eine Möglichkeit, die gewünschte Ausgabe zu erhalten:

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

Sie können es auch in doppelte Anführungszeichen setzen, aber dann müssen Sie die $ S maskieren, damit die Shell sie nicht als Variablen auflöst, und die Backticks, damit die Shell die Befehlsersetzung nicht sofort ausführt ::

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

Ich werde nicht näher darauf eingehen, warum sich Ihre Versuche so verhalten, wie sie es tun, denn Michael Mrozeks Antwort deckt dies gut ab. Kurz gesagt, alles zwischen einfachen Anführungszeichen ('…') Wird wörtlich interpretiert (und insbesondere das erste ' Markiert das Ende der Literalzeichenfolge), während ` Und $ Behalten ihre spezielle Bedeutung zwischen "…".

Es gibt kein Anführungszeichen in einfachen Anführungszeichen, daher können Sie kein einfaches Anführungszeichen in eine Zeichenfolge in einfachen Anführungszeichen setzen. Es gibt jedoch eine Redewendung, die so aussieht:

echo 'foo'\''bar'

Dies gibt foo'bar Aus, da das Argument für echo aus der dreistelligen Zeichenfolge foo in einfachen Anführungszeichen besteht, die mit dem einzelnen Zeichen ' (Erhalten) verknüpft ist durch Schützen des Zeichens ' vor seiner besonderen Bedeutung durch das vorhergehende \), verkettet mit der einstelligen dreistelligen Zeichenfolge bar. Obwohl dies hinter den Kulissen nicht ganz der Fall ist, können Sie sich '\'' Als eine Möglichkeit vorstellen, ein einfaches Anführungszeichen in eine Zeichenfolge in einfachen Anführungszeichen aufzunehmen.

Wenn Sie komplexe mehrzeilige Zeichenfolgen drucken möchten, ist hier Dokument ein besseres Werkzeug. Ein hier vorhandenes Dokument besteht aus den beiden Zeichen <<, Gefolgt von einer Markierung wie <<EOF, Dann einigen Textzeilen und der Endmarkierung allein in der Zeile. Wenn der Marker in irgendeiner Weise in Anführungszeichen gesetzt wird ('EOF' Oder "EOF" Oder \EOF Oder 'E "" OF' oder ...), wird der Text wörtlich interpretiert (wie in der Single) Anführungszeichen, außer dass sogar ' ein gewöhnliches Zeichen ist). Wenn der Marker überhaupt nicht in Anführungszeichen gesetzt wird, wird der Text wie in einer Zeichenfolge in doppelten Anführungszeichen interpretiert, wobei $\` Ihren Sonderstatus beibehält (aber " Und Zeilenumbrüche werden wörtlich interpretiert).

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

Okay, das wird funktionieren: -

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

Hier testen: -

[[email protected] ~]$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '
 echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' ` 
1
Andy Smith

Gilles 'Vorschlag Die Verwendung eines Dokuments hier ist wirklich nett und funktioniert sogar in Skriptsprachen wie Perl. Als konkretes Beispiel, das auf seiner Antwort auf das Problem des OP basiert,

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;

Zugegeben, dieses Beispiel ist ein wenig erfunden, aber ich habe festgestellt, dass es eine nützliche Technik ist, um beispielsweise SQL-Anweisungen an psql (anstelle von cat) zu senden.

(Beachten Sie, dass jedes nicht-alphanumerische Nicht-Leerzeichen anstelle des # Im obigen generischen Anführungszeichen verwendet werden kann, aber der Hash schien für dieses Beispiel gut hervorzuheben und ist nicht als Kommentar behandelt.)

0
Randall