テキストストリームを読み取り、後で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
コマンド(ただし、エラーメッセージの言語にも影響します)。