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


248

次のスクリプトを使用します。

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

shdashここ)でこれを実行しようとすると、エスケープする必要がある括弧のために失敗します。しかし、私はしません(オクテットの間、またはバックスラッシュ自体をエスケープする必要があります\s\1)。ここでのルールは何ですか?いつ使用する必要があります{...}[...]?私がしていることと逃げる必要がないことのリストはありますか?


1
SEDで使用するためにパスを変換するためのbash関数をfunction sedPath { path=$((echo $1|sed -r 's/([\$\.\*\/\[\\^])/\\\1/g'|sed 's/[]]/\[]]/g')>&1) } #Escape path for use with sed
次に示します。– user2428118


Dura lex、sed sed
ニモ

回答:


282

ここには、シェルとsedの2つのレベルの解釈があります。

シェルでは、単一引用符自体を除き、単一引用符の間のすべてが文字どおりに解釈されます。単一引用符の間に単一引用符を効果的に書くには、単一引用符を'\''閉じます(単一引用符を1つ、リテラル単一引用符を1つ、単一引用符を1つ開きます)。

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

さらに、/ブラケット式の外側の正規表現で使用する場合は、前にバックスラッシュが必要です。s~/dir~/replacement~またはを書くことで、区切り文字として代替文字を選択できます\~/dir~p。BREに区切り文字を含める場合は、区切り文字の前にバックスラッシュが必要です。BREで特別な意味を持つ文字を選択し、それを文字どおりに含める場合は、3つのバックスラッシュが必要です。一部の実装では動作が異なる場合があるため、これはお勧めしません。

一言で言えば、ためにsed 's/…/…/'

  • 単一引用符の間に正規表現を記述します。
  • '\''正規表現で単一引用符で終わるために使用します。
  • $.*/[\]^これらの文字の前にバックスラッシュを置きます(ただし、ブラケット式の中には入れません)。(技術的には、あなたは前にバックスラッシュを置くべきではありません]が、私は扱う実装を知らない]\]ブラケット式の外側では異なります。)
  • ブラケット式の中では、-文字通り処理されるために、それが最初または最後であることを確認します([abc-]または[-abc]、ではなく[a-bc])。
  • ブラケット式の中では、^文字通り処理されるために、それが最初ではないことを確認してください([abc^]ではなくを使用してください[^abc])。
  • ]ブラケット式と一致する文字のリストに含めるには、最初の文字(または^否定セットの場合は最初の文字):[]abc]または[^]abc](not [abc]]nor[abc\]])にします。

置換テキスト:

  • &そして、\区切り文字(通常はそうであるように、バックスラッシュの後に指定して引用符で囲む必要/)や改行を。
  • \数字が続く特別な意味があります。\手紙によっていくつかの実装で特別な意味(特殊文字)が続き、\他のいくつかの文字は意味が続く\cか、c実装に依存します。
  • 引数(sed 's/…/…/')を単一引用符で囲ん'\''で、置換テキストに単一引用符を付けるために使用します。

正規表現または置換テキストがシェル変数に由来する場合、それを覚えておいてください

  • 正規表現はリテラル文字列ではなく、BREです。
  • 正規表現では、改行を次のように表現する必要があります\nsedパターン文字列に改行文字を追加する他のコードがない限り、これは一致しません)。ただし、一部のsed実装ではブラケット式内では機能しないことに注意してください。
  • 置換テキストで&\、、および改行を引用符で囲む必要があります。
  • 区切り文字は引用符で囲む必要があります(ただし、括弧式の中ではありません)。
  • 補間には二重引用符を使用しますsed -e "s/$BRE/$REPL/"

実際のワイルドカード文字(*)をエスケープするには、二重バックスラッシュ(\\*)を使用できます。例:echo "***NEW***" | sed /\\*\\*\\*NEW\\*\\*\\*/s/^/#/
danger89

43

発生している問題は、シェルの補間とエスケープによるものではありません。sedthe -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]

私は再びこの問題を抱えていたので、前回スクロールして解決策を見つけるのを忘れていました。再度、感謝します。
isaaclw

どうもありがとう。-r私の場合、オプションとして追加することが必要でした。
HelloGoodbye

15

シェル変数をsed式に補間したくない場合は、バックスラッシュを含むそれらの間のすべてがそのまま解釈されるため、式全体に単一引用符を使用します。

したがって、sedにs/\(127\.0\.1\.1\)\s/\1/一重引用符を付けて表示したい場合、シェルはその中の括弧やバックスラッシュに触れません。シェル変数を補間する必要がある場合は、その部分のみを二重引用符で囲みます。例えば

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

これにより、二重引用符でエスケープされないシェルメタキャラクターを覚える手間が省けます。


見たいのですseds/(127\.0\.1\.1)/...、それをそのままシェルスクリプトに入れてもうまくいきません。シェルが括弧に触れていないことについて言っていることは間違っているようです。質問を詳細に編集しました。
12

3
シェルは括弧に触れていません。sedはそれらを表示する必要があるため、バックスラーが必要です。 sed 's/(127\.0\.1\.1)/IP \1/'sedのニーズが見ているので失敗\(し、\)グループの構文については、ない()
カイルジョーンズ

facepalmマニュアルページにはありませんが、私が見つけたオンラインマニュアルにあります。これは正規表現では普通ですか?正規表現ライブラリ(Pythonなど)で使用する必要がなかったからですか?
12

3
従来のUnixコマンドには、基本的な正規表現と拡張正規表現があります。 詳細。sedは基本的な正規表現を使用するため、グループの構文にはバックスラッシュが必要です。PerlとPythonは、拡張された正規表現を超えました。私がいじくり回しているときに、「正規表現」と一見したときに紛らわしいbraがどのようなものかを示す非常に有益なチャートを見つけました。
カイルジョーンズ

1
また、単一引用符内で使用できない唯一の文字は単一引用符であると付け加えます。
enzotib
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.