変数拡張で欠落している引用符を削除してエスケープの後に隠されたアイデアは何ですか?

変数拡張で欠落している引用符を削除してエスケープの後に隠されたアイデアは何ですか?

コマンドは変数に保存され、シェルで実行できます(良い方法ではありませんが)。例:

command='ls -l A* "B\" type"'
$command

A、およびで"B\"始まるファイルが一覧表示されますtype"。パラメータの分離とワイルドカードを実行しますが、引用符とエスケープは削除しません。この動作により、配列をサポートしないシェルで変数を使用して任意の引数を渡すことは非常に困難であり、find他のコマンドを安全に結合することは不可能になりますfor(よく議論されています)。引用符のない変数拡張では、多くの文字が制御されないため、ワイルドカードの使用も制限されます( `'"*?\nリテラルを含むワイルドカードシーケンスを保存して正しく再利用できません)。

状況は次のとおりです非常に変数の引用符とエスケープシーケンスが異なる場合は処理できます。しかし、なぜほとんどのシェルは実際にこれをしないのですか?私が気づいていないいくつかのあいまいな考慮事項を考慮して特別に設計されているのか、それとも互換性を維持するために渡されたのでしょうか?同様の質問があることがわかります。Bash変数拡張が引用符を保持するのはなぜですか?そして「変数のコマンド」での引用/エスケープ/拡張の問題この動作は議論されていますが、そこにある回答では原因については説明しません。

ベストアンサー1

この動作により、変数を使用して任意のパラメータを渡すことは非常に困難です[...]

おそらく。ただし、拡張結果をすべての一般的なコマンドライン処理に適用せずに、任意の引数全体を渡すことは不可能です。

たとえば、どこかからファイル名を取得してコマンドに渡そうとするスクリプトを考えてみましょう。以下でファイル名を取得するとしますread

echo -n "please enter filename: "
read -r filename
some command "$filename"

ユーザーが同様のファイル名を入力すると、単一引用符が原因で構文エラーが発生し、don't stop me now.txt実行が中断されます。some command

同様に、スクリプトが例のように実行され、myscript don*.txtコマンドライン引数からファイル名を取得する場合:

filename=$1
some command "$filename"

もう一度$filename(または$1すでに)一重引用符が含まれています。

さらに悪いことに、ファイル名またはユーザー入力文字列に代替コマンドを含めることができます。ただ変数を使う任意のコマンドを実行してください。スクリプト作成者は、スクリプトの外部から読み取られたすべての文字列にエスケープ文字を厳しく追加する必要があります。さらに、人々はそうしません、そしてシェルはツールとして使用するのが安全ではありません。

(必要に応じて拡張を処理する必要はなく、引用符とバックスラッシュのみを処理できますが、ペアのない引用符の問題はまだ存在します。)

もちろん、read必要なエスケープだけを追加する必要があると言うかもしれませんが、他のすべてのタイプの入力に追加する必要がありますか?文字列操作はどのように機能しますか?引用符も処理する必要がありますか?${#var}可変長と同じくらい単純なものでさえ、実装するのにより多くの費用がかかります。複数の異なる引用符付き文字列を含む変数の長さはどういう意味ですか?

最後に考慮するのが最善です。パスワードスクリプトとスクリプトの違いデータスクリプトはそれを処理し、コードに明示的に設定された方法でのみデータが処理されるように難読化されないように構成します。変数拡張を引用したことを覚えていれば、これがシェルが行うこととほぼ同じです。

変数のデータをそのまま使用することは、他のすべてのプログラミング言語でも同様です。たとえば、このCコードスニペットから印刷された文字列は、引用符"foo bar"でランタイム環境で解析されません。

char *s = "\"foo bar\"";
printf("%s\n", s);

s = "foo()"同様に、逆の場合、printf()呼び出しは関数を呼び出さずにfoo()文字列のみを印刷しますfoo()。 (解釈された言語とコンパイルされた言語について議論したい場合は、例をPerlまたはPythonに変更できます。)


今、これはあなたの提案が2022年に私にとって良い考えではない理由についての議論です。しかし、実際には「理由」と設計の根拠を尋ねています。これは2022年ではなく、1970年代と1980年代頃に起こりました。ウィキペディアで言及Bourne Shellの最初のリリースは1979年に行われました。それはずっと前、従来のコンピューティングの歴史が今よりずっと短かった時でした。これで、シェルアレイなどの他のツールを作成するのに役立つ可能性のある遅れた判断の利点があります。より速いコンピュータとより多くのメモリ。

私はデザインの背後に隠された実際の説明が「これが彼らが最初にすべてを見つけたときに念頭に置いたものですが、何が理由であるのか止まっていました」というフレーズによるものかもしれないという考えを無視しません。以前のバージョンとの互換性は2つの方法で機能します。少なくとも現在、配列を含むシェルとはまったく異なるシェルがあります。

おすすめ記事