it-swarm-eu.dev

Proč echo ignoruje mé citáty?

Příkaz echo nezahrnuje celý text, který jsem mu dal. Pokud například:

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

Výstupy:

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

Jednotlivé uvozovky (') Měl jsem ve svém echo příkazu nejsou zahrnuty. Pokud přepnu na dvojité uvozovky:

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

echo nevydává vůbec nic! Proč v prvním příkladu vynechává jednotlivé uvozovky a ve druhém neuvádí nic? Jak se dostanu na výstup přesně toho, co jsem napsal?

24
Diana

Vaše Shell interpretuje citace, obě ' a ", ještě než se dostanou k echo. Obecně jsem jen vložil do svého argumentu dvojité uvozovky, i když jsou zbytečné; například:

$ echo "Hello world"
Hello world

Takže v prvním příkladu, pokud chcete do výstupu zahrnout doslovné uvozovky, je třeba jim buď uniknout:

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

Nebo je třeba použít již v citovaném argumentu (ale nemůže to být stejný druh nabídky, nebo budete muset stejně uniknout):

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

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

Ve druhém příkladu provádíte substituci příkazu uprostřed řetězce:

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

Věci, které začínají $ jsou také zpracovány speciálně Shell - zachází s nimi jako s proměnnými a nahrazuje je jejich hodnotami. Protože s největší pravděpodobností žádná z těchto proměnných není ve vašem prostředí nastavena, ve skutečnosti se právě spustí

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

Protože grep vidí pouze jeden argument, předpokládá se, že argument je vzor, ​​který hledáte, a že místo, ze kterého by měla číst data, je stdin, takže blokuje čekání na vstup. Proto se zdá, že váš druhý příkaz právě visí.

K tomu nedojde, pokud argument zadáte jednoduše do nabídky (což je důvod, proč váš první příklad téměř fungoval), takže je to jeden způsob, jak získat požadovaný výstup:

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

Můžete to také dvakrát citovat, ale pak budete muset uniknout $s, takže je Shell nerozlišuje jako proměnné, a backticks, takže Shell neprovádí ihned substituci příkazu:

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

Nebudu podrobně zkoumat, proč se vaše pokusy chovají tak, jak to dělají, protože odpověď Michaela Mrozka to dobře pokrývá. Stručně řečeno, vše mezi jednoduchými uvozovkami ('…') je interpretován doslovně (a zejména první ' označuje konec literálového řetězce), zatímco ` a $ si zachovává svůj zvláštní význam mezi "…".

V jednoduchých uvozovkách není citace, takže do jednoho uvozovkového řetězce nemůžete vložit jednu nabídku. Zdá se však, že to vypadá takto:

echo 'foo'\''bar'

Toto vytiskne foo'bar, protože argument k echo je tvořen jednocitovaným tříznakovým řetězcem foo, zřetězeným s jediným znakem ' (získané ochranou znaku ' ze svého zvláštního významu přes předchozí \), zřetězené jednorázovým řetězcem tří znaků bar. Takže i když to není úplně to, co se děje v zákulisí, můžete si představit '\'' jako způsob, jak zahrnout jednu citaci do jednoho řetězce.

Pokud chcete tisknout složité víceřádkové řetězce, lepším nástrojem je zde dokument . Dokument se skládá ze dvou znaků << následuje značka, například <<EOF, pak několik řádků textu, pak samotná koncová značka na jejím řádku. Pokud je značka uvedena jakýmkoli způsobem ('EOF' nebo "EOF" nebo \EOF nebo „E“ „OF“ nebo…), pak je text interpretován doslovně (jako uvnitř jednoduchých uvozovek, až na to, že sudé ' je obyčejný znak). Pokud značka není uvozena vůbec, pak je text interpretován jako ve dvojitě uvozeném řetězci s $\` si zachovává svůj zvláštní status (ale " a nové řádky jsou interpretovány doslovně).

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

Dobře, bude to fungovat: -

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

Testování zde: -

[[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ův návrh použití dokumentu zde je opravdu pěkné a funguje dokonce i ve skriptovacích jazycích, jako je Perl. Jako konkrétní příklad na základě jeho odpovědi na otázku 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;

Je pravda, že tento příklad je trochu vymyšlený, ale zjistil jsem, že je to užitečná technika, řekněme, zasílání příkazů SQL na psql (místo cat).

(Všimněte si, že jakýkoli nealfanumerický znak bez mezer lze použít místo # Ve výše uvedeném obecném citačním konstruktu, ale zdá se, že hash vyniká v tomto příkladu dobře a je není považováno za komentář.)

0
Randall