shスクリプトでsedを使用するときにどの文字をエスケープする必要がありますか?

shスクリプトでsedを使用するときにどの文字をエスケープする必要がありますか?

次のスクリプトを使用してください。

#!/bin/sh
sed 's/(127\.0\.1\.1)\s/\1/' [some file]

sh(ここ)で実行しようとすると、dashエスケープする必要がある角かっこが失敗します。しかし、私はいいえバックスラッシュ自体はエスケープする必要があります(オクテット間または\sまたはから\1)。ここにはどんなルールがありますか?またはを使用する必要があるときは{...}どうすればよいですか[...]?逃げる代わりにすべきことのリストがありますか?

答え1

これには、シェルとsedという2つのレベルの説明があります。

シェルでは、一重引用符自体を除いて、一重引用符間のすべての内容が文字通り解釈されます。一重引用符の間に一重引用符を作成して効果的に追加できます'\''(一重引用符、リテラル一重引用符、開いた一重引用符)。

Sedが使用するもの基本正規表現。 BREでは、文字セット()内を除いて文字通り$.*[\^処理するために、文字の前にバックスラッシュを付けて引用する必要があります。[…]文字、数字は(){}+?|引用しないでください。いくつかの実装では、それらのいくつかを引用することができます。シーケンス\(、、、\)および\n一部の実装では、、、\{および\}その他のバックスラッシュ+英数字は特別な意味を持ちます\+。一部の実装では、特定の場所から引用を解除することができます。\?\|$^

/また、角かっこ式の外側の正規表現に表示するには、前にバックスラッシュを追加する必要があります。たとえばs~/dir~/replacement~、;を作成して、代替文字を区切り文字として選択できます。\~/dir~pBREに含めるには、区切り記号の前にバックスラッシュが必要です。 BREで特別な意味を持つ文字を選択して文字通り含めたい場合は、3つのバックスラッシュが必要です。一部の実装では動作が異なるため推奨されません。

つまり、次のようになりますsed 's/…/…/'

  • 一重引用符の間に正規表現を作成します。
  • '\''一重引用符で正規表現を終了するために使用されます。
  • バックスラッシュをこれらの文字の前に追加し、その文字の前にのみ追加します$.*/[\]^(角かっこ式内には追加しません)。 (技術的に前のバックスラッシュを追加してはいけませんが]、角括弧式の外部で合計を別々に処理する実装を見たことはありません]。)\]
  • 角かっこ式内で文字通り処理するには、最初または最後(または、でない)であることを-確認してください。[abc-][-abc][a-bc]
  • 角かっこ式内で^文字通り処理するには、次のようにする必要があります。いいえまず(使用するには[abc^]、使用しない[^abc])。
  • ]角かっこ式に一致する文字のリストに含めるには、その文字を最初の文字(または^否定セットの場合は最初の文字)にします。[]abc]または[^]abc][abc]]または[abc\]]ない)。

代替テキストでは:

  • &区切り記号(通常)\や改行文字などの前にバックスラッシュを付けて引用する必要があります。/
  • \次の数字には特別な意味があります。\次の文字は一部の実装で特別な意味(特殊文字)を持ち、\他の文字が続く内容は実装によって異なり\cます。c
  • 代替テキストに一重引用符を追加するsed 's/…/…/'には、引数()を一重引用符で囲みます。'\''

正規表現または代替テキストがシェル変数から来た場合は、次のことを覚えておいてください。

  • 正規表現はリテラル文字列ではなくBREです。
  • 正規表現では、改行は次のように表現する必要があります(パターンスペースに改行を追加する他のコードがない場合は\n絶対一致しません)。sedただし、一部の実装では角括弧式内では機能しませんsed
  • 代替テキストでは、&および\改行文字を引用する必要があります。
  • 区切り文字は引用符で囲む必要があります(角括弧式には含まれません)。
  • 補間に二重引用符を使用して下さい: sed -e "s/$BRE/$REPL/"

答え2

発生した問題は、シェル補間とエスケープによるものではありません。これは、 sed-r--regexp-extendedオプションを渡さずに拡張正規表現構文を使用したいからです。

sed行を変更してみてください

sed 's/(127\.0\.1\.1)\s/\1/' [some file]

到着

sed -r 's/(127\.0\.1\.1)\s/\1/' [some file]

意図した通りに良くなると確信しています。

デフォルトでは、sedは次の構文を必要とするデフォルトの正規表現(grepスタイルの考え方)を使用します。

sed 's/\(127\.0\.1\.1\)[ \t]/\1/' [some file]

答え3

sed式にシェル変数を挿入したくない場合は、式全体に単一引用符を使用してください。これにより、バックスラッシュを含むその間のすべての内容がそのまま解釈されます。

したがって、sedがこれを見ることができるようにするには、s/\(127\.0\.1\.1\)\s/\1/周囲に一重引用符を入れます。これにより、シェルは括弧やバックスラッシュに触れません。シェル変数を挿入する必要がある場合は、その部分を二重引用符で囲みます。例えば

sed 's/\(127\.0\.1\.1\)/'"$ip"'/'

これにより、二重引用符でエスケープされていないシェルメタ文字を記憶する手間が少なくなります。

答え4

sedは基本正規表現(BRE)のみをサポートするように指定するPOSIX標準に基づいていますが、実際にはsedコマンドにはBSD(Mac OS)とGNU(Linuxディストリビューション)の2つの異なるバージョンがあることに言及する価値があると思います。 。 。各バージョンは似ていますが、独自のPOSIX標準拡張機能を実装し、さまざまなプラットフォームでsedの機能に影響を与える可能性があります。したがって、あるシステムで期待通りに動作するsedコマンドの正しい構文は、実際には他のシステムではまったく異なる結果として解釈される可能性があります。これにより、エスケープや特殊文字の使用に関して予期しない動作が発生する可能性があります。

POSIX 標準へのこれらの拡張は、sed の GNU バージョンでより一般的になりがちであり、特に BSD バージョンに比べて厳しくないフォーマットの利便性を提供することがよくあります。しかし、GNU sedはいくつかの特殊文字機能を受け入れますが、実際にはPOSIXと互換性がありません。また、GNU sedの基本正規表現と拡張正規表現(ERE)の唯一の実際の違いは、次の特殊文字の動作です。

「?」、「+」、括弧、中括弧(「{}」)、および「|」

そうかもしれませんが、「|」、「?」そして「+」のような特殊文字はPOSIX構文標準に厳密に準拠しているため、BSD sedでサポートが制限またはサポートされていません。 GNU sedと同様の方法でこれらの文字を含めると、sedを使用するスクリプトに移植性と機能の問題が発生することがよくあります。 POSIX BRE構文は、特に\|、+、\?、`、\'、\<、>、\b、\B、\w、および\などの特定のエスケープシーケンスの意味を定義しないことにも注目に値します。ワット、。

BSD / Mac OSバージョンのsedを実行している場合は、特定の特殊文字の動作をシミュレートするのが少し難しいかもしれませんが、ほとんどの場合は完了できます。たとえば、+は次のようにPOSIX準拠の方法でエミュレートできます。 {1,} と \? は次のようになります。 {0,1} ただし、制御文字シーケンスは通常サポートされません。もちろん、可能であればGNU sedを使用するのが最も簡単ですが、両方のプラットフォームで機能が必要な場合は、移植性を確保するためにPOSIX機能のみを使用する必要があることに注意してください。 MacユーザーでBSD sedの代わりにGNU sedを利用したい場合は、Homebrewをインストールして$brew install gnu-sedコマンドラインからGNU sedをダウンロードできます。

全体的に、バージョンの違いによって、正しい構文が何であるか、またはどの文字をエスケープする必要があるかを実際に決定できます。これは、元の質問と承認された回答の追加のコンテキストを提供し、他の人がスクリプトとコマンドの使用の最終目標に沿って進む方法を考えるのに役立つことを願っています。

関連情報