375

私のbashスクリプトには、sedパターンで使用する必要がある外部(ユーザーから受け取った)文字列があります。

REPLACE="<funny characters here>"
sed "s/KEYWORD/$REPLACE/g"

リテラル置換として$REPLACE安全に受け入れられるように、文字列をエスケープするにはどうすればよいですか?sed

注:KEYWORD、一致しないなどのダム部分文字列です。ユーザーが提供するものではありません。

4

14 に答える 14

325

警告: これは改行を考慮していません。より詳細な回答については、代わりにこの 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 のコメントを参照してください。

編集済み:以前は考慮されていなかったいくつかのまれなケースのため、上記のコマンドは数回変更されました。詳細は編集履歴をご確認ください。

于 2010-04-24T18:35:19.547 に答える
110

sed コマンドを使用すると/、区切り記号の代わりに他の文字を使用できます。

sed 's#"http://www\.fubar\.com"#URL_FUBAR#g'

二重引用符は問題ではありません。

于 2015-04-30T11:40:55.677 に答える
52

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
于 2009-01-02T18:31:15.427 に答える
35

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
于 2012-05-06T01:46:06.793 に答える
12

あなたは間違った質問をしていることがわかります。私も間違った質問をしました。それが間違っている理由は、最初の文の冒頭にある「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"}"
于 2015-12-29T22:51:55.223 に答える
1

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
于 2014-11-14T23:34:43.547 に答える
0

これは、私が少し前に使用した AWK の例です。新しいAWKSを印刷するのはAWKです。AWK と SED は似ているので、良いテンプレートになるかもしれません。

ls | awk '{ print "awk " "'"'"'"  " {print $1,$2,$3} " "'"'"'"  " " $1 ".old_ext > " $1 ".new_ext"  }' > for_the_birds

過剰に見えますが、どういうわけか引用符の組み合わせが機能して、 ' をリテラルとして出力し続けます。次に、私の記憶が正しければ、変数は「$1」のように引用符で囲まれているだけです。試してみてください。SED でどのように機能するか教えてください。

于 2009-01-02T17:58:37.660 に答える
-1

" と ' の周りのシェル制限で発生するすべての喜びを忘れないでください。

そう(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"
于 2013-11-22T15:29:11.137 に答える
-2

パターンを置換するために渡すランダムなパスワードを生成している場合はsed、ランダムな文字列のどの文字セットに注意するかを選択します。sed値を base64 としてエンコードして作成されたパスワードを選択した場合、base64 で使用可能であり、置換パターンの特殊文字でもある文字のみが存在します。その文字は「/」であり、生成するパスワードから簡単に削除できます。

# password 32 characters log, minus any copies of the "/" character.
pass=`openssl rand -base64 32 | sed -e 's/\///g'`;
于 2016-06-01T02:24:35.720 に答える
-2

sed コマンドの変数値を置き換えるだけの場合は、例を削除してください。

sed -i 's/dev-/dev-$ENV/g' test to sed -i s/dev-/dev-$ENV/g test
于 2017-09-01T06:35:20.697 に答える