引用符なしでechoを実行するのは危険ですか?

引用符なしでechoを実行するのは危険ですか?

いくつかの同様のトピックを見たことがありますが、変数を引用しないという内容がありますが、これは望ましくない結果をもたらす可能性があることを知っています。

このコードを見て、次のコード行が実行されたときに実行するものを挿入できるかどうか疑問に思います。

echo run after_bundle

答え1

上記のメモを追加してください。@Kusalanandaのすばらしい回答

echo run after_bundle

問題ありません。これは、3つのパラメータのどの文字もechoシェル固有の文字を含むように渡されないためです。

そして(ここでさらに言及したいことは)これらのバイトをシェル固有の文字に変換できるシステムロケールはありません。

これらの文字はすべて何ですか?POSIX呼び出しポータブル文字セット。これらの文字は、POSIXシステムのすべての文字セットに同じ方法で表示され、エンコードする必要があります。

したがって、コマンドラインはロケールに関係なく同じように解釈されます。

この移植可能な文字セットの外側の文字を使用し始めた場合は、その文字がシェルに特別でない場合でも、その文字を引用することをお勧めします。他のロケールでは、その文字を構成するバイトが別の文字として解釈される可能性があるためです。シェルスペシャルになります。コマンドを使用するかecho他のコマンドを使用するかは、echoシェルがコードを解析する方法ではありません。

たとえば、UTF-8では次のようになります。

echo voilà | iconv -f UTF-8 -t //TRANSLIT

エンコーディングはà0xc3 0xa0です。シェルスクリプトに対応するコード行があり、文字セットがUTF-8以外のロケールを使用しているユーザーがシェルスクリプトを呼び出す場合、これらの2バイトは非常に異なる文字を生成できるようになりました。

たとえば、fr_FR.ISO8859-15ロケールでは、一般的なフランス語ロケールは、フランス語を含む標準のシングルバイト文字セット(英語を含むほとんどの西ヨーロッパ言語と同じ)を使用し、0xc3バイトは文字として解釈され、Ã0xa0は文字として解釈されます。非文字セット。空白文字を破棄します。

NetBSD³などの一部のシステムでは、切り捨て防止スペースは次のように処理されます。スペース文字(isblank()trueを返し、一致)なので、[[:blank:]]シェルと同様にbash構文内のトークン区切り文字として扱われます。

echoこれは、as引数で実行するのではなく$'voil\xc3\xa0'as引数で実行しているため、正しく印刷されない$'voil\xc3'ことを意味しますvoilà

BIG5、BIG5-HKSCS、GB18030、GBKなどの中国語文字セットの場合、状況はさらに悪化します。この文字セットにはエンコーディングに、、|(最悪の例を挙げると)文字を含む文字が多くあります`。ではありませんが、0x5cでエンコードされているため、ほとんどのツールではまだ処理されています。\¥\\

たとえば、中国語のロケールを使用している場合は、zh_CN.gb18030次のスクリプトを作成できます。

echo 詜 reboot

スクリプトは、詜 rebootGB18030またはGBKを使用するロケール、唰 rebootBIG5またはBIG5-HKSCSを使用するロケール、ASCIIを使用するCロケール、またはISO8859-15またはUTF-8を使用するロケールとしてreboot出力されます。 GB18030 エンコーディングは0xd4 0x7c で、0x7c は ASCII エンコーディングなので、以下を|実行します。

 echo �| reboot

uname(しかし、�はロケールでレンダリングされた0xd4バイトを表します)reboot

$ echo $'echo \u8a5c uname' | iconv -t gb18030 > myscript
$ LC_ALL=zh_CN.gb18030 bash ./myscript | sed -n l
\324| uname$
$ LC_ALL=C bash ./myscript | sed -n l
Linux$

unameすでに実行中)。

したがって、私の提案は、移植可能な文字セットの外側の文字を含むすべての文字列を引用することです。

\ただし、andのエンコーディングはこれらの文字の一部のエンコーディングに見られるため、or(and / orはまだ特別です)を使用せずに移植可能な文字セットの外側の文字を参照することをお勧めし`ます。\"..."$'...'`\'...'

'私はロケールの文字セットにエンコーディングを含む文字(もちろんそれ自体を除く)があるシステムを知らないので、'これは'...'最も安全です。

一部のシェルは、$'\uXXXX'Unicodeコードポイントに基づく文字表現もサポートしています。zshWindowsやWindowsなどのシェルでは、bash文字はロケールの文字セットエンコーディングに挿入されます。ただし、文字セットにその文字がないと、予期しない動作が発生する可能性があります。これにより、シェルコードにASCII以外の文字を挿入することを防ぎます。

したがって、上記は次のようになります。

echo 'voilà' | iconv -f UTF-8 -t //TRANSLIT
echo '詜 reboot'

または:

echo $'voil\u00e0'
echo $'\u8a5c reboot'

(これらの文字を持たないロケールで実行すると、スクリプトがクラッシュする可能性があります。)

またはより良い理由は\echoまたは少なくとも一部 echo実装、少なくともUnix互換実装):

printf '%s\n' 'voilà' | iconv -f UTF-8 -t //TRANSLIT
printf '%s\n' '詜 reboot'

\最初の引数も特別なので、printfエンコードが含まれる場合はASCII以外の文字を避けるのが最善です\。)

次のタスクも実行できます。

'echo' 'voilà' | 'iconv' '-f' 'UTF-8' '-t' '//TRANSLIT'

(これは少し過剰ですが、ポータブル文字セットにどの文字があるのか​​わからない場合は、心を楽にすることができます)

また、古代`...`の形式のコマンド置換(他のレベルのバックスラッシュ処理を導入)を絶対に使用しない$(...)でください。


1は技術的にユーティリティechoに引数として渡され(呼び出し方法を知らせる)、3は今日のほとんどのシェルに組み込まれているので、3つの引数リストを持つファイルのエミュレーションはシェルで行われます。引数リストは、コマンドが主に機能する引数であるため、2番目の引数(to)で始まると考えるのが一般的です。echoargv[0]argcechoexec()/bin/echoargv[1]argv[argc - 1]

²注目すべき例外の1つは、文字セットにNor文字が含まれていja_JP.SJISないFreeBSDシステムのとんでもないロケールです。\~

³多くのシステム(FreeBSD、Solaris、GNUシステムを除く)はU + 00A0を[[:blank:]]UTF-8ロケールとして扱いますが、他のロケール(たとえばISO8859-15を使用するシステム)ではそうするシステムはほとんどありません。そのような問題。

答え2

特定の状況をターゲティング

echo run after_bundle

引用は必要ありません。パラメータechoは静的文字列であり、変数の拡張やコマンドの置換などを含まないため、引用符は必要ありません。それは「たった二つの言葉」です。スティーブンは指摘した。、彼らはさらに構成されていますポータブル文字セット)。

「危険」は、シェルが拡張または解釈できる変数データを処理するときに発生します。この場合、シェルが正しい操作を実行し、結果が期待通りになるように注意する必要があります。

次の2つの質問には関連情報が含まれています。


echo場合によっては、このサイトの回答で潜在的に有害なコマンドを「保護」するために使用されます。たとえば、次のようにファイルを削除したり、ファイルを新しいターゲットに移動したりする方法を示します。

echo rm "${name##*/}.txt"

または

echo mv "$name" "/new_dir/$newname"

実際にファイルを削除したり名前を変更したりする代わりに、端末にコマンドが出力されます。その後、ユーザーはコマンドを確認し、まともに見えることを確認してから削除してecho再実行できます。

コマンドはecho run after_bundleユーザーに指示することも、結果を知らずに実行するには危険すぎる「コメント付き」コードかもしれません。

このように使用するときは、echo変更されたコマンドが何をしているのかを知る必要があり、変更されたコマンドが実際に実行されていることを確認する必要があります。はい安全です(これもありますいいえリダイレクトが含まれており、パイプで使用すると機能しません。)

関連情報