Warum ignoriert das Echo meine Anführungszeichen?

24

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

   $ 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 ( '), die ich in meinem Echo-Befehl hatte, sind nicht enthalten. Wenn ich zu doppelten Anführungszeichen wechsle:

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

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

Michael Mrozek
quelle
3
Nicht ganz sicher, was Sie hier erreichen wollen. Warum verschachteln Sie eine Echo-Anweisung in einer anderen? Oder versuchen Sie buchstäblich, einen Befehl auszudrucken (für ein Beispiel oder ein solches)?
Andy Smith
Ich muss die Echoausgabe in eine andere Datei einfügen
Sie müssen erklären, was Sie versuchen zu tun. Zum Beispiel "Ich möchte den folgenden Text an eine Datei anhängen: '...'."
MikeyB
2
Ich habe versucht, dies für 5 Minuten zu bearbeiten, aber ich weiß ernsthaft nicht, was die gewünschte Ausgabe ist. Bearbeiten : Ok, ich denke, ich habe jetzt eine Vermutung, also habe ich versucht zu bearbeiten. Wenn es nicht das ist, was Sie vorhatten, lassen Sie es mich wissen
Michael Mrozek
1
@Michael - Wow - Wenn ich dir einen Repräsentanten für deine Bearbeitung geben könnte, wäre ich - ein guter Job, der dies zu einer wirklich großartigen Frage macht!
Randall

Antworten:

33

Ihre Shell interpretiert die Anführungszeichen, sowohl 'als auch ", bevor sie überhaupt ankommen echo. Im Allgemeinen setze ich meine Argumente in doppelte Anführungszeichen, um sie wiederzugeben, auch wenn sie nicht erforderlich sind. beispielsweise:

$ 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 in Anführungszeichen gesetzten Argument verwendet werden (aber es kann nicht dieselbe Art von Anführungszeichen 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 anfangen, $werden auch speziell von der Shell behandelt - sie werden als Variablen behandelt und durch ihre Werte ersetzt. 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 grepnur ein Argument angezeigt wird, wird davon ausgegangen, dass es sich bei dem Argument um das Muster handelt, nach dem Sie suchen, und dass die Position, von der die Daten gelesen werden sollen, stdin ist, sodass das Warten auf Eingaben blockiert wird. Deshalb scheint Ihr zweiter Befehl einfach zu hängen.

Dies passiert nicht, wenn Sie das Argument in 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 das $s schließen, damit die Shell sie nicht als Variablen auflöst, und die Backticks, damit die Shell die Befehlssubstitution nicht sofort ausführt:

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

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 wörtlichen Zeichenfolge), während `und $behalten ihre besondere Bedeutung zwischen "…".

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

echo 'foo'\''bar'

Dies wird ausgegeben foo'bar, weil das Argument to echoaus der in Anführungszeichen gesetzten dreistelligen Zeichenfolge besteht foo, die mit dem einzelnen Zeichen verkettet ist '(das durch Schützen des Zeichens 'vor seiner speziellen Bedeutung durch das Vorhergehende erhalten wird \) und mit der in Anführungszeichen gesetzten dreistelligen Zeichenfolge verkettet ist bar. Obwohl dies im Hintergrund nicht der '\''Fall ist , können Sie sich vorstellen , ein einfaches Anführungszeichen in eine Zeichenfolge mit einfachen Anführungszeichen einzufügen.

Wenn Sie komplexe mehrzeilige Zeichenfolgen drucken möchten, ist das Dokument hier ein besseres Werkzeug . Ein Here-Dokument besteht aus zwei Zeichen, <<gefolgt von einer Markierung, z. B. <<EOFTextzeilen, und der Endmarkierung allein in der Zeile. Wenn der Marker in irgendeiner Weise in Anführungszeichen gesetzt wird ( 'EOF'oder "EOF"oder \EOF'E "" OF' oder ...), wird der Text wörtlich interpretiert (wie in einfachen Anführungszeichen, außer dass es sich sogar 'um ein gewöhnliches Zeichen handelt). Wenn der Marker überhaupt nicht in Anführungszeichen gesetzt ist, wird der Text wie eine doppelte Anführungszeichenfolge interpretiert, $\`wobei sein besonderer Status beibehalten wird (aber "und Zeilenumbrüche werden wörtlich interpretiert).

cat <<'EOF'
echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `
EOF
Gilles 'SO - hör auf böse zu sein'
quelle
1

Okay, das wird funktionieren: -

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

Testen Sie es hier: -

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

Gilles 'Vorschlag , ein Dokument hier zu verwenden, ist wirklich nett und funktioniert sogar in Skriptsprachen wie Perl. Als konkretes Beispiel, basierend auf seiner Antwort auf die Frage des 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;

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 anstelle des #obigen generischen Anführungszeichens ein beliebiges nicht-alphanumerisches Nicht-Leerzeichen verwendet werden kann. Der Hash schien jedoch für dieses Beispiel von Bedeutung zu sein und wird nicht als Kommentar behandelt.)

Randall
quelle
-1

Nehmen wir Ihr Kommando an

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

und teilen Sie es zuerst in Wörter auf, wobei Sie das Leerzeichen ohne Anführungszeichen als Trennzeichen verwenden:

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

Als nächstes führen wir eine Parametererweiterung durch: expand, $…aber nicht inside '…'. Da $2leer ist (es sei denn, Sie setzen es über zB set -- …), wird es durch einen leeren String ersetzt.

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

Führen Sie als Nächstes das Entfernen von Zitaten durch.

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

Diese Argumente werden dann an echo übergeben, das sie durch ein einzelnes Leerzeichen getrennt nacheinander ausgibt.

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

Ich hoffe, dass diese schrittweise Anleitung das beobachtete Verhalten klarer macht. Um das Problem zu vermeiden, schließen Sie einfache Anführungszeichen wie folgt:

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

Dies beendet die Zeichenfolge in einfachen Anführungszeichen, fügt dem Wort ein einfaches Anführungszeichen (ohne Anführungszeichen) hinzu und beginnt dann eine neue Zeichenfolge in einfachen Anführungszeichen, ohne das Wort zu trennen.

MvG
quelle