テキストストリームを読み取り、後でsed -fで実行されるsedコマンドのファイルを生成するスクリプトがあります。 。生成されるsedコマンドは次のようになります:
s/cid:[email protected]/https://mysite.com/files/1922/g
s/cid:[email protected]/https://mysite.com/files/1923/g
s/cid:[email protected]/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内のすべての正規表現メタ文字を確実にするためにスクリプトを改善するにはどうすればよいですか? 文字列はエスケープされ、適切に補間されますか?
承認された回答:
sの左側と右側で使用される変数をエスケープするには sedのコマンド (ここでは$lhs および$rhs それぞれ)、次のようにします:
escaped_lhs=$(printf '%sn' "$lhs" | sed 's:[][\/.^$*]:\&:g')
escaped_rhs=$(printf '%sn' "$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)または PCRE -Rを使用 (ssed )または拡張RE -Aを使用 / -X (ast )すべてに追加のRE演算子があります。
任意のデータを処理する際のいくつかの基本ルール:
-
echoを使用しないでください - 変数を引用する
- ロケールの影響を考慮してください(特にその文字セット:エスケープすることが重要です
sedコマンドは、sedと同じロケールで実行されます エスケープされたを使用したコマンド 文字列(および同じsedコマンド)たとえば) - 改行文字を忘れないでください(ここで、
$lhsかどうかを確認することをお勧めします いずれかが含まれ、アクションを実行します。
別のオプションは、perlを使用することです sedの代わりに 環境内で文字列を渡し、Qを使用します / E perl 文字通り文字列を取るための正規表現演算子:
A="$lhs" B="$rhs" perl -pe 's/Q$ENV{A}E/$ENV{B}/g'
perl (デフォルトでは)ロケールの文字セットの影響を受けません。上記のように、文字列はバイトの配列と見なされるだけで、ユーザーに対してどの文字(存在する場合)を表すかは関係ありません。 sedを使用 、ロケールをCに固定することで、同じことを実現できます。 LC_ALL=Cを使用 すべてのsed コマンド(ただし、エラーメッセージの言語にも影響します)。