shellのquotingとは何か?展開を制御する
shellのquotingは、テキストをリテラルとして扱うよう指示し、空白が引数を分割するか、変数やwildcardが展開されるかを制御します。
quotingはshellスクリプトの中で最もエラーが起きやすい部分の1つであり、最も重要な部分の1つでもあります。値をシングルクォート、ダブルクォート、あるいはクォートなしで囲むかによって、shellがそれを空白で分割するか、変数を展開するか、wildcardをglobするかが決まります。CIでの「pathに空白が入るまでは動く」というバグのほとんどは、クォート漏れに帰着します。
なぜquotingが存在するか
shellは通常、入力を空白で分割し、変数とwildcardを展開します。quotingはその一部またはすべてを一時停止し、空白や特殊文字を含め、テキストを書かれたとおりに渡せるようにします。
シングルクォートとダブルクォート
- シングルクォートは完全にリテラルで、内部は何も展開されません。
- ダブルクォートは変数とコマンドの置換を許しますが、word splittingとglobbingは防ぎます。
- クォートなしは、完全な分割、展開、globbingを意味します。
典型的なバグ
クォートしないと、$FILEに空白が含まれる場合、shellがそれを2つの引数に分割するため、rm $FILEは壊れます。rm "$FILE"と書くとそれを1つに保ち、これが変数をほぼ常にダブルクォートで囲むべき理由です。
quotingと展開の組み合わせ
ダブルクォートはほとんどのスクリプトでちょうどよい選択です。$VARを介して変数の値を得られる一方、それらの値の中の空白はそのまま保たれ、wildcardが誤って展開されることもありません。
CIにおけるquoting
CIのpathや入力には、予期しなかった空白や特殊文字が含まれることがよくあります。"${INPUT}"のようにすべての変数展開をダブルクォートで囲むことは、pipelineでの謎めいたword splittingの失敗を避けるための最も効果的な習慣です。
マネージドrunnerでの堅牢なスクリプト
Latchkeyのrunnerでは、任意のLinux shellと同じquotingのルールが適用されます。set -uを一貫したダブルクォートと組み合わせると、未定義の変数と誤ってクォートされた変数の両方を、buildを壊す前に捉えられます。
重要なポイント
- quotingはword splittingと、変数およびwildcardの展開を制御します。
- シングルクォートはリテラルで、ダブルクォートは変数を展開しつつ空白をそのまま保ちます。
"$VAR"のようにすべての変数をダブルクォートで囲むと、CIスクリプトのバグのほとんどを防げます。