web-dev-qa-db-ja.com

変数内の二重引用符をエスケープする

このコマンドをファイルに入れて後で実行したいと思います。

ln -s "$xr"/ya.txt ~

私は(1)でそれを行うことができます:

cat > zu.sh <<eof
ln -s "$xr"/ya.txt ~
eof

または(2):

printf 'ln -s "%s"/ya.txt ~\n' "$xr" > zu.sh

または(3):

echo "ln -s '$xr'/ya.txt ~" > zu.sh

または(4):

printf 'ln -s %q/ya.txt ~\n' "$xr" > zu.sh

または(5):

printf 'ln -s "%s"/ya.txt ~\n' "${xr//\"/\\\"}"

ただし、各ソリューションには問題があります。 (1)または(2)の変数に二重引用符が含まれている場合、それらは失敗します。 (3)の変数に単一引用符が含まれていると、失敗します。 (4)は良いですが、 POSIXによって定義されています ではありません。 (5)は良いですが a Bashism です。 (1)または(2)を使用して変数内の二重引用符をエスケープするのが最善の選択肢のようですが、別の方法で実行できますか?

4
Steven Penny

Awkライブラリ svnpenn/stdlib を使用して、引用符、バックスラッシュ、ドル記号でテストし、すべてのパスをバックティックします。

$ awklib 'BEGIN {printf "ln -s %s/ya.txt ~\n", sh_escape(ARGV[1])}' "2'2"
ln -s 2\'2/ya.txt ~

$ awklib 'BEGIN {printf "ln -s %s/ya.txt ~\n", sh_escape(ARGV[1])}' '2"2'
ln -s '2"2'/ya.txt ~

$ awklib 'BEGIN {printf "ln -s %s/ya.txt ~\n", sh_escape(ARGV[1])}' '2\2'
ln -s '2\2'/ya.txt ~

$ awklib 'BEGIN {printf "ln -s %s/ya.txt ~\n", sh_escape(ARGV[1])}' '2$2'
ln -s '2$2'/ya.txt ~

$ awklib 'BEGIN {printf "ln -s %s/ya.txt ~\n", sh_escape(ARGV[1])}' '2`2'
ln -s '2`2'/ya.txt ~

免責事項:このライブラリを作成しましたが、より適切なオプションが存在する場合は、この回答を削除できます。

0
Steven Penny

これは安全だと思います:

_esc() {
    printf "%s\n" "$1" | sed -e "s/'/'\"'\"'/g" -e "1s/^/'/" -e "\$s/\$/'/"
}
_

文字列を一重引用符で囲んで、入力文字列の_$_、_`_、_\_、および_"_は関係ない 、既存の_'_文字を_'"'"'_に変換します(つまり、単一引用符を終了し、単一の単一引用符を二重引用符で囲み、次に単一引用符を再度引用します)。

そこに $(...)コマンド置換 を使用するのは魅力的でしたが、その後、入力の末尾の改行をすべて使用します。代わりに、最初と最後の行の最初と最後に、2番目と3番目の sed スクリプト自体によって開始引用符と終了引用符が挿入されます。埋め込まれた改行はそのまま残されますが、問題ありません。

出力はシェルにコピーして戻すのに適しています。私が考案できる最も病理学的なケースでも(最初にテスト文字列を作成するために Bash ANSI-C引用_$'...'_ を使用します)、その後ではない):

_bash-4.4$ esc $'abc\ndef ghi\'jkl$mno`pqr\\stu\\\'vwx\n\n\n'
'abc
def ghi'"'"'jkl$mno`pqr\stu\'"'"'vwx


'
bash-4.4$ echo 'abc
> def ghi'"'"'jkl$mno`pqr\stu\'"'"'vwx
>
>
> '
abc
def ghi'jkl$mno`pqr\stu\'vwx



bash-4.4$ dash
$ echo 'abc
def ghi'"'"'jkl$mno`pqr\stu\'"'"'vwx


'> > > >
abc
def ghi'jkl$mno`pqr\stu\'vwx



$
_

これを変数xr=$(esc "$xr")に入れて、ヒアドキュメント内または他の場所で後で通常の置換に使用するのが安全です。

4
Michael Homer