似たようなトピックをいくつか見ましたが、それらは変数を引用しないことに言及しています。
私はこのコードを見ましたが、このコード行が実行されたときに実行するものを注入できるかどうか疑問に思っていました:
echo run after_bundle
似たようなトピックをいくつか見ましたが、それらは変数を引用しないことに言及しています。
私はこのコードを見ましたが、このコード行が実行されたときに実行するものを注入できるかどうか疑問に思っていました:
echo run after_bundle
回答:
特定の場合
echo run after_bundle
引用符は必要ありません。への引数echo
は変数の展開やコマンドの置換などを含まない静的文字列であるため、引用符は必要ありません。これらは「2語のみ」です(Stéphaneが指摘しているように、ポータブル文字セットからさらに構築されます)。
「危険」は、シェルが展開または解釈する可能性がある変数データを処理するときに発生します。このような場合、シェルが正しいことを行い、その結果が意図したとおりになるように注意する必要があります。
次の2つの質問には、それに関する関連情報が含まれています。
echo
このサイトの回答で潜在的に有害なコマンドを「保護」するために使用されることがあります。たとえば、次のコマンドを使用して、ファイルを削除する方法、またはファイルを新しい宛先に移動する方法を示します。
echo rm "${name##*/}.txt"
または
echo mv "$name" "/new_dir/$newname"
これにより、実際にファイルを削除または名前変更する代わりに、端末にコマンドが出力されます。その後、ユーザーはコマンドを検査し、問題がないと判断し、を削除してecho
再度実行します。
コマンドecho run after_bundle
は、ユーザーへの指示である場合もあれば、「コメントアウトされた」コードであり、危険すぎて結果を知らずに実行できない場合もあります。
このecho
ように使用すると、変更されたコマンドが何をするかを知る必要があり、変更されたコマンドが実際に安全であることを保証する必要があります(リダイレクトが含まれていて、パイプラインでの使用が機能しないなどの可能性はありません)。
echo rm "first file.txt" "second file.txt"
から、どのような方法が異なっているecho rm "first" "file.txt" "second" "file.txt"
の両方からの出力が同じであること、。シェルコマンドを出力として生成する場合は、渡されたと評価される構文の引用を再生成するか同等のものを使用する必要があります。printf '%q ' rm "first file.txt" "second file.txt"; echo
argv
sh
は、まったく珍しいパターンではなく、人々が「foo
コマンドラインで実行するとなぜ機能するのかと尋ねられますが、このスクリプトecho
は行の前に正確な文字列を出力するのではありませんか? 」ここでいつも起こります 要するに、デバッグ出力は、バグが隠されている場合は役に立ちません。バグが引用に関連している場合echo
は、明らかになりません。
@Kusalanandaの細かい答えに加えて、もう 1つ注意点があります。
echo run after_bundle
echo
シェルに特別な文字を含むように渡されたこれらの3つの引数の文字は1つもないため、問題ありません。
そして、(ここで強調したい追加のポイント)これらのバイトがシェルに特有の文字に変換されるシステムロケールはありません。
これらの文字はすべて、POSIXが移植可能な文字セットと呼ぶものに含まれています。これらの文字は、POSIXシステムのすべての文字セットに存在し、同じようにエンコードされる必要があります²。
そのため、そのコマンドラインはロケールに関係なく同じように解釈されます。
ここで、そのポータブル文字セット以外の文字を使用し始めた場合、それらがシェルにとって特別でなくても、引用符で囲むことをお勧めします。別のロケールでは、それらを構成するバイトが異なる文字として解釈される可能性があるためです。シェルに特別です。それはあなたが使っているのかecho
他のコマンドを使っているのかであることに注意してください、問題はecho
シェルではなくそのコードを解析する方法にあります。
たとえば、UTF-8の場合:
echo voilà | iconv -f UTF-8 -t //TRANSLIT
これà
は0xc3 0xa0としてエンコードされます。さて、シェルスクリプトにそのコード行があり、シェルスクリプトが文字セットがUTF-8ではないロケールを使用するユーザーによって呼び出された場合、これらの2バイトは非常に異なる文字になる可能性があります。
たとえば、fr_FR.ISO8859-15
ロケールでは、フランス語をカバーする標準の1バイト文字セット(英語を含むほとんどの西ヨーロッパ言語で使用されるものと同じ)を使用する典型的なフランス語ロケールで、0xc3バイトはÃ
文字として解釈され、0xa0は非改行スペース文字。
そして、NetBSD³のようないくつかのシステムでは、非改行スペースは空白文字と見なされ(isblank()
その場合はtrueを返し、と一致します[[:blank:]]
)、シェルはbash
そのため、構文でトークン区切り文字として扱います。
代わりに実行するのであることを意味しecho
て$'voil\xc3\xa0'
引数として、彼らはそれを実行し$'voil\xc3'
、それが印刷されないことを意味します引数としてvoilà
正しく。
それは、エンコーディングと同じエンコーディングが含まれている多くの文字を持っているBIG5、BIG5-HKSCS、GB18030、GBKのような中国の文字セットとたくさん悪化し|
、`
、\
マイクロソフト漢字別名、を除いて、(また、その滑稽SJIS(最悪に名前を付けます)それはの¥
代わりに\
ありますが\
、0x5cとしてエンコードされているので、ほとんどのツールと同様に扱われます)。
たとえば、zh_CN.gb18030
中国語ロケールの場合、次のようなスクリプトを記述します。
echo 詜 reboot
このスクリプトは詜 reboot
、GB18030またはGBK 唰 reboot
を使用するロケール、BIG5またはBIG5-HKSCS を使用するロケールで出力しますが、ASCIIを使用するCロケールまたはISO8859-15またはUTF-8を使用するロケールではreboot
、GB18030エンコーディングが実行されるため、 of 詜
は0xd4 0x7cであり、0x7cは|
ASCII のエンコーディングなので、次を実行します。
echo �| reboot
(ただし、0xd4バイトを表すことはロケールでレンダリングされます)。uname
代わりに害の少ないものを使用する例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
実行されました)。
したがって、ポータブルキャラクタセット以外の文字を含むすべての文字列を引用することをお勧めします。
ただし、\
および`
のエンコーディングはこれらの文字の一部のエンコーディングに含まれているため、\
or "..."
または$'...'
(or 内`
および/または\
まだ特殊)を使用せずに'...'
、ポータブル文字セット外の文字を引用することをお勧めします。
'
エンコーディングにのエンコーディングが含まれている(もちろん、それ自体以外の)文字セットが含まれているロケールを持つシステムは知らない'
ので、これら'...'
が間違いなく最も安全であるべきです。
いくつかのシェル$'\uXXXX'
では、Unicodeコードポイントに基づいて文字を表現する表記法もサポートされています。zsh
およびのようなシェルでbash
は、文字はロケールの文字セットでエンコードされて挿入されます(ただし、その文字セットにその文字がない場合、予期しない動作が発生する可能性があります)。これにより、シェルコードに非ASCII文字を挿入する必要がなくなります。
上記のように:
echo 'voilà' | iconv -f UTF-8 -t //TRANSLIT
echo '詜 reboot'
または:
echo $'voil\u00e0'
echo $'\u8a5c reboot'
(ただし、これらの文字を持たないロケールでスクリプトを実行すると、スクリプトが壊れる可能性があります)。
または、(または少なくともいくつかの実装、少なくともUnix準拠の実装)に\
も特別であるため、より良い:echo
echo
printf '%s\n' 'voilà' | iconv -f UTF-8 -t //TRANSLIT
printf '%s\n' '詜 reboot'
(\
の最初の引数でも特殊であることに注意してくださいprintf
。したがって、ASCII以外の文字も、のエンコードを含む可能性がある場合に備えて避けるほうが適切です\
)。
次のこともできることに注意してください:
'echo' 'voilà' | 'iconv' '-f' 'UTF-8' '-t' '//TRANSLIT'
(それはやり過ぎですが、どのキャラクターがポータブルキャラクターセットに含まれているかわからない場合は、ある程度安心できます)
また、古い`...`
形式のコマンド置換(別のレベルのバックスラッシュ処理を導入する)を使用し$(...)
ないでください。代わりに使用してください。
¹技術的に、echo
またに引数として渡されるecho
ユーティリティ(それが呼び出されたどのようにそれを伝えるために)、それはだargv[0]
とargc
ほとんどのシェルでは、今日も、3であるecho
組み込みされ、その結果、exec()
の/bin/echo
でシミュレートされた3つの引数のリストを持つファイルシェル。コマンドが主に作用する引数であるため、引数のリストを2番目の引数(argv[1]
to argv[argc - 1]
)から始めることも一般的です。
²これの顕著な例外ja_JP.SJIS
は、文字セットに文字\
も~
文字もないFreeBSDシステムの滑稽なロケールです!
many多くのシステム(FreeBSD、Solaris、GNUのものではない)はU + 00A0を[[:blank:]]
UTF-8ロケールと見なしますが、ISO8859-15を使用する他のロケールでは、この種の問題を回避できるものはほとんどないことに注意してください。
echo
...」、私は、コマンドに渡される2つの引数を数えecho
、私は数えることができる引数は、run
とafter_bundle
どのようにあなたを説明するために、ケアカウントして3つの引数を得ましたか?
echo
)。ユーティリティに(exec -a foo /bin/echo --help)
任意の最初の引数を渡す方法については、GNUシステムおよびGNUシェルを参照してください/bin/echo
。
$0
シェルの位置パラメータと似ています。
iconv
するESC
に変換されますが'
。試してみてください(例として):printf '\x1b'|iconv -f utf8 -t IBM-937|xxd
'
。試してくださいprintf '\u2804' | iconv -f utf8 -t BRF | xxd
。になるコードポイントが多いエンコーディングがあります'
。UCS-4の約8695のコードポイントはになり'
ます。試してくださいprintf '\U627' | iconv -cf utf-8 -t UCS-4
。いくつかの(37)エンコーディングは、文字0x127をに変換し'
ます。試してくださいprintf '\U127' | iconv -cf utf8 -t UCS2 |xxd