stackoverflowの回答 にあるように、bash変数を二重引用符でカプセル化することは、ユーザー入力を無害化するかなり安全な方法であると理解しています。
Awk変数はどうですか?たとえば、次のような場合:
awk -v SOURCEIP="$SOURCEIP" -v REVERSEDNS="$REVERSEDNS" '{
gsub(/^_TMPSOURCEIP_/, SOURCEIP);
gsub(/^_TMPREVERSEDNS_/, REVERSEDNS);
print
}' /home/foo/footemplate
Gsub行の変数を引用符で囲む必要がありますか?したがって、次のようになります。
awk -v SOURCEIP="$SOURCEIP" -v REVERSEDNS="$REVERSEDNS" '{
gsub(/^_TMPSOURCEIP_/, "SOURCEIP");
gsub(/^_TMPREVERSEDNS_/, "REVERSEDNS");
print
}' /home/foo/footemplate
それとも違いはありませんか?
次の2つの例は、違いを示しています。
$ echo _TMP_ | awk -v VAR='some "text"' '{ gsub(/_TMP_/, VAR) ; print }'
some "text"
$ echo _TMP_ | awk -v VAR='some "text"' '{ gsub(/_TMP_/, "VAR") ; print }'
VAR
VAR
が引用符で囲まれていない場合、awk
は値some "text"
を持つ変数として扱います。 VAR
が引用符の内側にある場合、awkはそれを3文字の文字列として扱います。
MORE:bash
にはサニタイズの問題があります。検討してください:
$ VAR="rm important_file" ; $VAR
上記はimportant_file
を消去します。このように、bash
はマクロ言語のようなものです。変数の代わりに使用して、結果を実行しようとします。 awk
は異なります。検討してください:
$ echo _TMP_ | awk -v VAR='var); print $1' '{ gsub(/_TMP_/, VAR) ; print }'
var); print $1
awk
は、実行する可能性のあるコマンドではなく、単なるテキストのようにVAR
を扱います。
ただし、bash
にawk
スクリプトを変更させると、問題が発生する可能性があります。上記の例では、awk
スクリプトはすべて単一引用符で囲みました。これはbash
がそれらを乱用するのを防ぎます。
(申し訳ありませんが、あなたの質問をあまりにも早く読んだので、私の答えのいくつかは要点の少しずれていますが、それでもあなたや一部にとって役立つかもしれないので、そのままにしておきます)
ここで考慮すべき点がいくつかあります。
awk
ではなく、POSIXシェルで変数を引用符で囲まずに(コマンドの引数のようにリストコンテキストで)残すのは、split + glob演算子です。
もし、するなら:
_cmd foo=$var
_
ここで、_$var
_は_* *
_です。
シェルに_$var
_の特別なシェル変数の値に基づいて_$IFS
_のコンテンツを分割するように要求するのではなく、デフォルトでは空白になっています。上記のように、これにより_foo=*
_と_*
_が得られ、それぞれに対してグロビングを実行します。つまり、_foo=*
_を_foo=
_で始まる現在のディレクトリ内のすべてのファイル名に展開します。 _*
_を非表示ではないすべてのファイル名に。
したがって、実際には、Shell変数は、awk
の引数であるかどうかにかかわらず、ほとんど常に引用する必要があります。これは、シェルコマンド置換(_`...`
_および$(...)
)およびシェル算術展開($((...))
)にも適用されます。
awk
に渡すその他の問題は、awk
(シェルではない)が_-v var=value
_(およびGNU awk
4.2以降、 値が_@/
_で始まり_/
_で終わる場合、これは正規表現型の変数として扱われます )。
たとえば、_-v var='\n/\n/'
_は、awk
var
変数の内容を_<newline>/<newline>/
_ではなく_\n/\n/
_に設定します。これは、次のように定義されたawk
変数にも適用されます。
_awk '...' var=value
_
展開せずにデータをawk
に渡すには、ENVIRON
またはARGV
awk配列を使用できます。
_var=$value awk 'BEGIN {var=ENVIRON["var"]} ...'
_
(上記は、(配列以外の変数への)シェル変数の割り当てであるため、split + globはできません。これは、変数を囲む引用符を省略できるまれなケースの1つです)
または:
_awk 'BEGIN {var=ARGV[1]; delete ARGV[1]} ...' "$value"
_
awk
変数そのsplit + globはシェル(誤)機能にすぎません。 awk
言語は完全に異なる言語です。
awk
では、変数は_$varname
_ではなくvarname
を参照し、引用符を使用して文字列を紹介します。したがって、_"varname"
_はvarname
文字列であり、varname
は変数を参照します。
厳密に言うと、Shell変数の引用は無害化ではなく、split + glob演算子を使用している変数を引用しないです。ほとんどの言語では固定文字列を引用符で囲みますが、シェルではそれが逆になります。すべてのものは文字列であり、引用符は特別な動作を防ぐために使用されます。特に変数はほとんど常に引用符で囲まれる必要があります70年代のBourneシェルでは理にかなっていますが、現代のシェルでは邪魔です。zsh
はそれを部分的に修正した唯一のシェルです)。
シェルまたはawkは、ユーザーが指示しない限り、独自の変数に格納されているコードを評価または解釈しません。
_var='foo; rm -f var'
echo $var
# or
echo "$var"
_
変数の内容がシェルコードとして評価されることはありません(ただし、最初のコードはスプリットとグロビングを実行するため、悲惨な結果を招く可能性があります(たとえば、_var='/*/*/*/*/../../../../*/*/*/*/../../../../*/*/*/*'
_を使用)。次のものが必要です。
_eval "echo $var"
# or
sh -c "echo $var"
_
シェルコードとして評価/解釈されるため。
awk
には、そのようなeval
機能はありません。 Perl
/python
します。
ただし、相互汚染に注意してください。 awk
で実行するコードとして、シェルに変数データ(Shell変数内)を渡すことができます。
_awk '{print "'"$var"': " $0}'
_
_$var
_ Shell変数に次の例が含まれている場合は危険です:
_var='test"; print "foo" > /etc/passwd; print "blah'
_
シェルが実行するため:
_["awk", "{print \"test\"; print \"foo\" > /etc/passwd; print \"blah: \" $0}"]
_
またはその逆:
_awk '{system("echo foo: " $0)}' < file
_
ここで、awk
は次のようにシェルを実行します。
_["sh", "-c", "echo foo: content-of-the-line"]
_
file
の各行について(そして_; rm -rf /
_のような行が何をするかを考えてください)。
awk
とsh
の間だけではありません。変数/制御されていないデータが別のインタープリターによってコードとして評価される可能性がある場合は常に注意する必要があります。次に例を示します。
_sed "s/$regexp/blah/g"
_
sed
の言語は限られていますが、_regexp='//;w /etc/passwd; s/
_ 'のように、まだ害を及ぼす可能性があります。
または:
_find . -exec sh -c "echo {}" \;
_
これらの問題を回避するために、2つの一般的なアプローチがあります。
変数を1つのインタープリターから別のインタープリターに変換します。これは、上記のシェル-> awkまたはfind-> shの場合に機能します。変化のように:
_awk '{print "'"$var"': " $0}'
_
に:
_awk -v awk_var="$var" '{print awk_var ": " $0}'
_
そして:
_find . -exec sh -c "echo {}" \;
_
に:
_find . -exec sh -c 'echo "$1"' sh {} \;
_
しかし、シェル-> sed、またはawk->シェルの場合は機能しません。
1が不可能な場合は、変数をサニタイズして、問題となる可能性のある文字を削除またはエスケープする必要があります。に、
_awk '{system("echo foo: " $0)}'
_
シェルに関する限り、_$0
_をクリーンな文字列に変換する必要があります。 1つのオプションは、各文字の前にバックスラッシュを付けることですが、それは改行では機能しません(ここでは問題ではありません)。もう1つは、文字列を単一引用符で囲み、各単一引用符をエスケープすることです。
_awk 'function escape(s) {
gsub(/'\''/,"&\\\\&&",s)
return "'\''" s "'\''"
}
{system("echo foo: " escape($0))}'
_
Awk変数をsystemに渡す場合は、シェルで引用する必要があります。
function quote(str, d, m, x, y, z) {
d = "\47"; m = split(str, x, d)
for (y in x) z = z d x[y] d (y < m ? "\\" d : "")
return z
}
例:
system(sprintf("ffmpeg -i %s outfile.m4a", quote(ARGV[1])))