私のbashスクリプトには、sedパターンで使用する必要がある外部(ユーザーから受け取った)文字列があります。
REPLACE="<funny characters here>"
sed "s/KEYWORD/$REPLACE/g"
リテラル置換として$REPLACE
安全に受け入れられるように、文字列をエスケープするにはどうすればよいですか?sed
注:はKEYWORD
、一致しないなどのダム部分文字列です。ユーザーが提供するものではありません。
警告: これは改行を考慮していません。より詳細な回答については、代わりにこの SO-questionを参照してください。(ありがとう、エド・モートンとニクラス・ピーター)
すべてをエスケープすることは悪い考えであることに注意してください。Sed は、特別な意味を得るために多くの文字をエスケープする必要があります。たとえば、置換文字列で数字をエスケープすると、後方参照になります。
Ben Blank が言ったように、置換文字列でエスケープする必要がある文字は 3 つだけです (自分自身をエスケープし、ステートメントの末尾にはスラッシュを、すべて置換には & を使用します)。
ESCAPED_REPLACE=$(printf '%s\n' "$REPLACE" | sed -e 's/[\/&]/\\&/g')
# Now you can use ESCAPED_REPLACE in the original sed statement
sed "s/KEYWORD/$ESCAPED_REPLACE/g"
文字列をエスケープする必要がある場合KEYWORD
は、次のものが必要です。
sed -e 's/[]\/$*.^[]/\\&/g'
そして、以下で使用できます:
KEYWORD="The Keyword You Need";
ESCAPED_KEYWORD=$(printf '%s\n' "$KEYWORD" | sed -e 's/[]\/$*.^[]/\\&/g');
# Now you can use it inside the original sed statement to replace text
sed "s/$ESCAPED_KEYWORD/$ESCAPED_REPLACE/g"
/
区切り文字以外の文字を使用する場合は、上記の式のスラッシュを使用している文字に置き換える必要があることに注意してください。説明については、PeterJCLaw のコメントを参照してください。
編集済み:以前は考慮されていなかったいくつかのまれなケースのため、上記のコマンドは数回変更されました。詳細は編集履歴をご確認ください。
sed コマンドを使用すると/
、区切り記号の代わりに他の文字を使用できます。
sed 's#"http://www\.fubar\.com"#URL_FUBAR#g'
二重引用符は問題ではありません。
replace 句で特別に扱われる 3 つのリテラル文字は、(/
句を閉じるため)、\
(エスケープ文字、後方参照、&c.)、および&
(置換に一致を含めるため) のみです。したがって、次の 3 つの文字をエスケープするだけです。
sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"
例:
$ export REPLACE="'\"|\\/><&!"
$ echo fooKEYWORDbar | sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"
foo'"|\/><&!bar
Pianosaurus の正規表現に基づいて、キーワードと置換の両方をエスケープする bash 関数を作成しました。
function sedeasy {
sed -i "s/$(echo $1 | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo $2 | sed -e 's/[\/&]/\\&/g')/g" $3
}
使用方法は次のとおりです。
sedeasy "include /etc/nginx/conf.d/*" "include /apps/*/conf/nginx.conf" /etc/nginx/nginx.conf
あなたは間違った質問をしていることがわかります。私も間違った質問をしました。それが間違っている理由は、最初の文の冒頭にある「In my bash script...」です。
私は同じ質問をし、同じ間違いをしました。bash を使用している場合は、sed を使用して文字列を置換する必要はありません ( bash に組み込まれている置換機能を使用する方がはるかにクリーンです)。
たとえば、次のようなものの代わりに:
function escape-all-funny-characters() { UNKNOWN_CODE_THAT_ANSWERS_THE_QUESTION_YOU_ASKED; }
INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A="$(escape-all-funny-characters 'KEYWORD')"
B="$(escape-all-funny-characters '<funny characters here>')"
OUTPUT="$(sed "s/$A/$B/g" <<<"$INPUT")"
bash 機能を排他的に使用できます。
INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A='KEYWORD'
B='<funny characters here>'
OUTPUT="${INPUT//"$A"/"$B"}"
awk を使用してください - よりクリーンです:
$ awk -v R='//addr:\\file' '{ sub("THIS", R, $0); print $0 }' <<< "http://file:\_THIS_/path/to/a/file\\is\\\a\\ nightmare"
http://file:\_//addr:\file_/path/to/a/file\\is\\\a\\ nightmare
これは、私が少し前に使用した AWK の例です。新しいAWKSを印刷するのはAWKです。AWK と SED は似ているので、良いテンプレートになるかもしれません。
ls | awk '{ print "awk " "'"'"'" " {print $1,$2,$3} " "'"'"'" " " $1 ".old_ext > " $1 ".new_ext" }' > for_the_birds
過剰に見えますが、どういうわけか引用符の組み合わせが機能して、 ' をリテラルとして出力し続けます。次に、私の記憶が正しければ、変数は「$1」のように引用符で囲まれているだけです。試してみてください。SED でどのように機能するか教えてください。
" と ' の周りのシェル制限で発生するすべての喜びを忘れないでください。
そう(kshで)
Var=">New version of \"content' here <"
printf "%s" "${Var}" | sed "s/[&\/\\\\*\\"']/\\&/g' | read -r EscVar
echo "Here is your \"text\" to change" | sed "s/text/${EscVar}/g"
パターンを置換するために渡すランダムなパスワードを生成している場合はsed
、ランダムな文字列のどの文字セットに注意するかを選択します。sed
値を base64 としてエンコードして作成されたパスワードを選択した場合、base64 で使用可能であり、置換パターンの特殊文字でもある文字のみが存在します。その文字は「/」であり、生成するパスワードから簡単に削除できます。
# password 32 characters log, minus any copies of the "/" character.
pass=`openssl rand -base64 32 | sed -e 's/\///g'`;
sed コマンドの変数値を置き換えるだけの場合は、例を削除してください。
sed -i 's/dev-/dev-$ENV/g' test to sed -i s/dev-/dev-$ENV/g test