「sed」置換に補間された文字列がすべてのメタ文字をエスケープすることを保証する方法


21

テキストストリームを読み取り、後でで実行されるsedコマンドのファイルを生成するスクリプトがありますsed -f。生成されるsedコマンドは次のとおりです。

s/cid:image002\.gif@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1922/g
s/cid:image003\.gif@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1923/g
s/cid:image004\.jpg@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1924/g

sedコマンドを生成するスクリプトが次のようなものであると仮定します。

while read cid fileid
do
    cidpat="$(echo $cid | sed -e s/\\./\\\\./g)"
    echo 's/'"$cidpat"'/https:\/\/mysite.com\/files\/'"$fileid"'/g' >> sedscr
done

cid文字列内のすべての正規表現メタ文字が適切にエスケープおよび補間されるようにスクリプトを改善するにはどうすればよいですか?

回答:


24

(こことそれぞれ)のsコマンドの左側と右側で使用される変数をエスケープするには、次のようにします。sed$lhs$rhs

escaped_lhs=$(printf '%s\n' "$lhs" | sed 's:[][\/.^$*]:\\&:g')
escaped_rhs=$(printf '%s\n' "$rhs" | sed 's:[\/&]:\\&:g;$!s/$/\\/')

sed "s/$escaped_lhs/$escaped_rhs/"

$lhs改行文字を含めることはできません。

つまり、LHSでは、すべての正規表現演算子(][.^$*)、エスケープ文字自体(\)、および区切り文字(/)をエスケープします。

RHSで、あなただけのエスケープする必要があり&、セパレーター、バックスラッシュと改行文字(あなたが最後のものを除いて、各行の末尾にバックスラッシュを挿入してください($!s/$/\\/))。

あなたが使用を前提としている/あなたのセパレータとしてsed sコマンドやあなたが有効にしないことを拡張するRE-r(GNU sed/ ssed/ ast/ busybox sed)または-E(BSD系、ast最近GNU、最近のbusybox)またはPCREs-Rssed)または増補のREをして-A/ -Xast)はすべてに追加のRE演算子があります。

任意のデータを扱うときのいくつかの基本ルール:

  • 使用しないでください echo
  • 変数を引用する
  • ロケールの影響を考慮します(特にその文字セット:エスケープ sedコマンドは、たとえばsedエスケープされた文字列(および同じsedコマンド)を使用するコマンドと同じロケールで実行されることが重要です)
  • 改行文字を忘れないでください(ここで何か$lhsが含まれているかどうかを確認し、アクションを実行できます)。

別のオプションは、文字列を使用するperl代わりに使用sedし、環境で文字列を渡し、文字列を文字通りに取るために\Q/ \E perlregexp演算子を使用することです。

A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'

perl(デフォルトでは)ロケールの文字セットの影響を受けません。上記では、文字列をバイトの配列と見なすだけで、ユーザーにとってどのような文字(存在する場合)を考慮する必要はありません。を使用sedするCLC_ALL=C、すべてのsedコマンドのロケールをwithに修正することで同じことが実現できます(ただし、エラーメッセージの言語にも影響します)。


二重引用符をエスケープする必要がある場合はどうなりますか?
メノン

@Menon、二重引用符はに特別なものsedではありません。エスケープする必要はありません。
ステファンシャゼル

これは、ワイルドカードを使用したパターンマッチングには使用できませんか?
メノン

@Menon、いいえ、find'sのようなワイルドカードパターンマッチング-nameは、正規表現とは異なります。そこから脱出?*バックスラッシュ、そして[
ステファンシャゼラス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.