ユーザーの入力を受け入れ、すべての特殊文字を「\」+文字に置き換えるスクリプト「test.sh」を作成したいと思います。私のスクリプト:
#!/bin/bash
echo 'input='"$1"
arg=`echo "$1" | sed 's:[]\[\^\$\.\*\/]:\\&:g'`
echo 'modified input='"$arg"
私のコマンドは、特殊文字のない文字列 "xy"で動作します。端末で次のコマンドを実行します。
test.sh xy
私は得る:
input=xy
modified input=xy
しかし、これを実行すると、次のようになります。
test.sh x.y
私は得る:
input=x.y
modified input=x&y
このスクリプトがなぜ機能しないのか理解できません。私は次のことを期待しています:
input=x.y
modified input=x\.y
問題はこのsedコマンドにあると思いますが、どこにいるのかわかりません。
sed 's:[]\[\^\$\.\*\/]:\\&:g'
答え1
グループを正しくキャプチャしていないようです。この試み?
sed 's:\([]\[\^\$\.\*\/]\):\\\1:g'
編集:気にしないでください。 &の関連性がわかりません。問題は、構文解析とサブシェル渡しのため、代替からスラッシュをさらにエスケープする必要があることです。
sed 's:[]\[\^\$\.\*\/]:\\\\&:g'
また、バックティックの代わりに$(command)を使用すると、追加の\は必要ありません。
答え2
したがって、アクションは、文字列内のsed
すべての特殊文字(私が追加した文字として定義されている)をエスケープする代替文字を作成することです。[]^$.*/
\
代替品は次のとおりです。
s/[][\^$.*/]/\\&/g
[...]
実際にセットの文字をエスケープする必要はありません(文字通り\
処理されるため、できないそこから何でも脱出してください)、私たちが確認する唯一のことは、これが]
まさに最初にあることです。
したがって、スクリプト(シェル関数で再構築または変更)は次のようになります。
function escape
{
printf '%s\n' "$1" | sed 's/[][\^$.*/]/\\&/g'
}
テスト:
$ escape 'hello world'
hello world
$ escape '*.*'
\*\.\*
$ escape '\/'
\\\/
$ escape '/\'
\/\\
$ escape 's/[][\^$.*/]/\\&/g'
s\/\[\]\[\\\^\$\.\*\/\]\/\\\\&\/g