GNU/Linux >> Linux の 問題 >  >> Linux

`sed`置換に補間された文字列がすべてのメタ文字をエスケープするようにするにはどうすればよいですか?

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

関連:特殊文字でsedを使用していますか?
Linux
  1. ファイル内の文字列を置き換える方法は?

  2. Sedを使用して複数行の文字列を置き換える方法は?

  3. バックスラッシュ文字で終わるすべての行を組み合わせるにはどうすればよいですか?

  1. 文字列をSedのスラッシュを含む文字列に置き換える方法は?

  2. Sed:最初の文字列を除く文字列のすべての出現を削除しますか?

  3. テキスト文字列を含まないすべてのファイルを検索するにはどうすればよいですか?

  1. Linuxコマンドラインで複数のファイルの文字列を置き換える方法

  2. *を介して隠しファイルを含むすべてのファイルを親ディレクトリに移動する方法

  3. すべてのカーネル リリースと互換性があるように Linux カーネル モジュールをビルドするにはどうすればよいですか?