web-dev-qa-db-ja.com

大文字と小文字を区別しない検索とsedによる置換

SEDを使用してログファイルからテキストを抽出しようとしています。あまり問題なく検索と置換を行うことができます。

sed 's/foo/bar/' mylog.txt

ただし、大文字と小文字を区別しない検索を行いたいです。私がグーグルで調べたところ、コマンドの最後にiを追加するように見えます:

sed 's/foo/bar/i' mylog.txt

ただし、これによりエラーメッセージが表示されます。

sed: 1: "s/foo/bar/i": bad flag in substitute command: 'i'

ここで何が間違っているのですか、どうすれば修正できますか?

73
Craig Walker

明確にするために:OnmacOS-Mojave(10.14)以降-sed- [〜#〜] bsd [〜#〜] 実装-大文字と小文字を区別しないマッチングをサポートしません-信じがたいですが、本当です。 以前受け入れられた回答 は、それ自体が [〜#〜] gnu [〜#〜] sedコマンドを示し、コメントに記載されているPerlベースのソリューション。

Perlソリューション外来文字でも動作するようにするには、UTF-8を介して、次のようなものを使用します。

Perl -C -Mutf8 -pe 's/öœ/oo/i' <<< "FÖŒ" # -> "Foo"
  • -Cは、現在のロケールがUTF-8ベースであると仮定して、ストリームとファイルのUTF-8サポートをオンにします。
  • -Mutf8は、ソースコードをUTF-8(この場合、-peに渡される文字列)として解釈するようPerlに指示します-これは、より詳細な-e 'use utf8;'.ありがとう、 マークリード

awkを使用することはオプションではありません、macOS上のawk(つまり、 BWK awk 、別名 BSD awk )はロケールを完全に認識していないようです-そのtolower()およびtoupper()関数は外来文字を無視します(およびsub()/gsub()は、大文字小文字を区別しないフラグで始まりません)。

65
mklement0

編集者のメモ:このソリューションは、macOSでは動作しません(そのままで)[〜#〜] gnu [〜#〜]sed。macOSには[〜#〜] bsd [〜#〜]sedが付属しています。

「I」を大文字にします。

sed 's/foo/bar/I' file
59
Wesley Rice

Mac OS X上のsedの別の回避策は、MacPortsまたはHomeBrewからgsedをインストールしてから、エイリアスsed='gsed'

23
user4854746

Macバージョンのsedは少し制限されているようです。これを回避する1つの方法は、sedの使用可能なバージョンを持つLinuxコンテナーを使用することです(Docker経由)。

cat your_file.txt | docker run -i busybox /bin/sed -r 's/[0-9]{4}/****/Ig'
2
user1307434

sed FAQ は、大文字と小文字を区別しない密接に関連するsearchに対処します。 a)sedの多くのバージョンがフラグをサポートしており、b)sedで行うのが面倒なので、むしろawkまたはPerlを使用する必要があることを指摘しています。

しかし、POSIX sedでそれを行うには、次の3つのオプションを提案します(ここでの置換に適応):

  1. 大文字に変換し、元の行をホールドスペースに保存します。ただし、これは置換の場合は機能しません。元のコンテンツが印刷前に復元されるため、大文字と小文字を区別しない一致に基づいて行を挿入または追加する場合にのみ適しています。

  2. おそらく、可能性はFOOFoo、およびfooに制限されています。これらは

    s/FOO/bar/;s/[Ff]oo/bar/
    
  3. 可能なすべての一致を検索するには、各文字に角括弧式を使用できます。

    s/[Ff][Oo][Oo]/bar/
    
2
Benjamin W.

私は同様のニーズがあり、これを思いつきました:

単純にすべてのファイルを見つけるためのこのコマンド:

grep -i -l -r foo ./* 

this_Shell.shを除外する(コマンドをthis_Shell.shというスクリプトに入れた場合)テキストfooをbarに置き換えるには:

grep -i -l -r --exclude "this_Shell.sh" foo ./* | tee  /dev/fd/2 | while read -r x; do sed -b -i 's/foo/bar/gi' "$x"; done 

変更されていないファイルのすべてのタイムスタンプを変更するのが好きではなかったため、この方法を選択しました。 grepの結果をフィードすると、ターゲットテキストを含むファイルのみを見ることができます(したがって、パフォーマンス/速度も向上する可能性があります)

使用する前に、必ずファイルをバックアップしてテストしてください。一部の環境では、スペースが埋め込まれたファイルでは機能しない場合があります。 (?)

0
gojimmypi

最初にパターンマッチングを行う場合、たとえば、

/pattern/s/xx/yy/g

次に、パターンの後にIを追加します。

/pattern/Is/xx/yy/g

例:

echo Fred | sed '/fred/Is//willma/g'

willmaを返します。 Iなしでは、文字列をそのまま(Fred)返します。

0
CBB