エコーが引用符を無視するのはなぜですか?

エコーが引用符を無視するのはなぜですか?

コマンドechoに私が提供したフルテキストは含まれていません。たとえば、これを行うと:

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

次のように出力されます。

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

私のechoコマンドの一重引用符()は'含まれていません。二重引用符に切り替えると、次のようになります。

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

echoまったく何も出力しません!最初の例では一重引用符を省略し、2番目の例では何も出力しないのはなぜですか?入力した内容を正確に出力するにはどうすればよいですか?

答え1

あなたのシェルは、およびを'含む引用符が"到着する前に解釈されていますecho。私は通常私の主張が不要であっても応答に二重引用符を使用します。

$ echo "Hello world"
Hello world

したがって、最初の例では、出力に文字通り引用符を含めるには、エスケープする必要があります。

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

または、すでに引用符で囲まれたパラメータに使用する必要があります(ただし、同じ種類の引用符ではありません。そうでなければ、とにかくエスケープする必要があります)。

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

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

2番目の例では、文字列の途中でコマンド置換を実行します。

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

で始まるものも$シェルによって排他的に扱われます。つまり、シェルはそれを変数として扱い、その値に置き換えます。これらの変数のどれもシェルに設定されていない可能性が高いため、実際には実行されます。

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

引数が1つしか表示されないため、引数が検索grep中のパターンであり、データを読み取る必要がある場所がstdinであると仮定して、入力を待つのをブロックします。そのため、2番目のコマンドが中断されたようです。

引数を一重引用符で囲むとこれは発生しません(これが最初の例がほぼ成功した理由です)、目的の出力を取得する1つの方法は次のとおりです。

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

二重引用符で囲むこともできますが、sをエスケープして$シェルがそれを変数に解析しないようにし、バックティックをエスケープしてシェルがすぐにコマンド置換を実行しないようにする必要があります。

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

答え2

私はあなたの試みがなぜそうなったのか詳細に説明しません。マイケル・モロジェクの回答これをとてもよく扱います。つまり、一重引用符()'…'の間のすべての内容は文字通り(特に'リテラル文字列の終わりを示す最初の引用)と解釈されますが、`ands$は特別な意味を維持します"…"

一重引用符の中には引用符がないため、一重引用符で囲まれた文字列内に一重引用符を入れることはできません。しかし、次のようなイディオムがあります。

echo 'foo'\''bar'

foo'barこれは、引数がecho一重引用符で囲まれた3文字の文字列で構成さfooれ、単一の文字で連結され(特殊な意味から文字を保護するために先行して得られます')、一重引用符で囲まれた3文字の文字列で連結されるために印刷されます。したがって、これがまさに後で何が起こっているのかわかりませんが、一重引用符で囲まれた文字列内に一重引用符を含める方法と考えることができます。'\bar'\''

複雑な複数行文字列を印刷するには、より良いツールは次のとおりです。ここのドキュメント。ここでドキュメントは、2 つの文字<<、その後にタグ(たとえば)、<<EOF数行のテキスト、最後にその行にある別の閉じたタグで構成されます。マークが何らかの方法で引用されている場合('EOF'または"EOF"または「E」「OF」または...)、テキストは文字通り解釈されます(evenが通常の文字である場合を\EOF除き、一重引用符の中のように)。'トークンがまったく引用されていない場合、テキストは二重引用符で囲まれた文字列のように解釈され、$\`特別な状態を維持します("改行文字は文字通り解釈されます)。

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

答え3

さて、これを行うことができます:-

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

ここでテストしてください: -

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

答え4

私たちはあなたの入札を行いましょう

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

まず、引用符なしのスペースを区切り文字として単語に分割します。

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

次に、パラメータ拡張を実行します。拡張$…ですが、内部的には拡張しません'…'。は空であるため、$2(設定しない限りset -- …)空の文字列に置き換えられます。

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

次に、引用符を削除します。

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

その後、これらの引数はechoに渡され、スペースで区切られ、1つずつ印刷されます。

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

この段階的な説明を通して、観察された動作がより明確になることを願っています。この問題を回避するには、次のように単一引用符をエスケープします。

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

これにより、一重引用符文字列が終了し、単語に(エスケープされた)一重引用符が追加され、単語を分割せずに新しい一重引用符文字列が始まります。

関連情報