sed / grepを使用して2つの単語間のテキストを抽出する方法


134

文字列の2つの単語間のすべてを含む文字列を出力しようとしています。

入力:

"Here is a String"

出力:

"is a"

使用:

sed -n '/Here/,/String/p'

エンドポイントが含まれていますが、含めたくありません。


8
入力が次の場合、結果はどうなりますHere is a Here Stringか?またはI Hereby Dub Thee Sir Stringy
ghoti

5
ご参考までに。コマンドは、ここではなく、ここに単語がある行と文字列という単語がある行の間のすべてを印刷することを意味します。
Hai Vu

他の一般的なsedFAQは、「特定の行の間のテキストを抽出する方法」です。これはstackoverflow.com/questions/16643288/...
tripleee

回答:


109
sed -e 's/Here\(.*\)String/\1/'

2
ありがとう!「Here is a one is a String」で「one is」と「String」の間のすべてを検索したい場合はどうなりますか?(sed -e 's / one is(。*)String / \ 1 /'?
user1190650

5
@ user1190650「こちらはこちら」も表示したい場合に有効です。あなたはそれをテストすることができます:echo "Here is a one is a String" | sed -e 's/one is\(.*\)String/\1/'。「one is」と「String」の間の部分だけが必要な場合は、正規表現を行全体に一致させる必要がありますsed -e 's/.*one is\(.*\)String.*/\1/'。sedでは、s/pattern/replacement/「各行の「パターン」を「置換」に置き換えて」と言います。「パターン」に一致するもののみが変更されるため、行全体を置き換える場合は、「パターン」を行全体に一致させる必要があります。
ブライアンキャンベル

9
これは、入力が次の場合に壊れますHere is a String Here is a String
Jay D

1
ケースの解決策を見るのは素晴らしいでしょう:「ここに何とか何とか文字列ここに1とか何とか文字列ここに2つは文字をblash blash文字列」出力は、ここと文字列の間の最初の部分文字列のみをピックアップする必要があります "
Jay D

1
@JayD sedは貪欲でないマッチングをサポートしていません。推奨される代替案については、この質問を参照してください。
ブライアンキャンベル

179

GNU grepは、ポジティブとネガティブの先読みとルックバックもサポートできます。あなたの場合、コマンドは次のようになります。

echo "Here is a string" | grep -o -P '(?<=Here).*(?=string)'

Hereand が複数ある場合はstring、最初Hereと最後から一致させるstringか、個別に一致させるかを選択できます。正規表現では、貪欲な一致(最初のケース)または貪欲でない一致(2番目のケース)と呼ばれます。

$ echo 'Here is a string, and Here is another string.' | grep -oP '(?<=Here).*(?=string)' # Greedy match
 is a string, and Here is another 
$ echo 'Here is a string, and Here is another string.' | grep -oP '(?<=Here).*?(?=string)' # Non-greedy match (Notice the '?' after '*' in .*)
 is a 
 is another 

31
GNU grepの-Pオプションはgrep* BSDに含まれているオプション、またはSVR4(Solarisなど)に付属しているオプションには存在しないことに注意してください。FreeBSDでは、PCRE(および先読み/後読み)をサポートするdevel/pcreを含むポートをインストールできますpcregrep。古いバージョンのOSXはGNU grepを使用していましたが、OSX Mavericksでは-P、オプションを含まないFreeBSDのバージョンから派生しています。
ghoti 2014

1
こんにちは、どうすれば明確なコンテンツのみを抽出できますか?
Durgesh Suthar

4
終了文字列「string」が複数回出現する場合、次の出現ではなく最後の出現を取得するため、これは機能しません。
Buttle Butkus

6
以下の場合はHere is a string a string両方 " is a "" is a string a "質問の要件ごとに有効な解答(引用符を無視する)、です。それはあなたがこれらのうちどれをあなたが望むかによります、そしてそれから答えはそれに応じて異なる場合があります。とにかく、あなたの要件のために、これは動作します:echo "Here is a string a string" | grep -o -P '(?<=Here).*?(?=string)'
anishsane

2
@BNDでは、pcregrepの複数行検索機能を有効にする必要があります。echo $'Here is \na string' | grep -zoP '(?<=Here)(?s).*(?=string)'
anishsane

58

受け入れ答えは前に可能性があり、テキストは削除されませんHereか後にString。この意志:

sed -e 's/.*Here\(.*\)String.*/\1/'

主な違いは、.*直前Hereと直後の追加ですString


あなたの答えは有望です。ただし、1つの問題。同じ行に複数の文字列がある場合、最初に見つかった文字列に抽出するにはどうすればよいですか?ありがとう
Mian Asbat Ahmad

@MianAsbatAhmad *量指定子をとの間HereString、貪欲でない(または怠惰な)ものにしたいとします。ただし、この Stackoverflowの質問によると、sedで使用される正規表現のタイプは、遅延数量詞(の?直後.*)をサポートしていません。通常、遅延量指定子を実装するには、一致させたくないトークンを除くすべてと照合しますが、この場合、単一のトークンだけではなく、文字列全体です。String
ウィーラー、

おかげで、私はawk、stackoverflow.com
questions / 51041463 /…

残念ながら、文字列に改行がある場合、これは機能しません
Witalo Benicio

それは想定されていません。.改行と一致しません。改行を一致させたい場合は、.などに置き換えることができます[\s\s]
ウィーラー、

35

Bashだけで文字列を取り除くことができます。

$ foo="Here is a String"
$ foo=${foo##*Here }
$ echo "$foo"
is a String
$ foo=${foo%% String*}
$ echo "$foo"
is a
$

PCREを含むGNU grepがある場合は、ゼロ幅アサーションを使用できます。

$ echo "Here is a String" | grep -Po '(?<=(Here )).*(?= String)'
is a

なぜこの方法はとても遅いのですか?この方法を使用して大きなhtmlページを削除する場合、10秒ほどかかります。
アダムジョンズ

@AdamJohns、どのメソッドですか?PCREは?PCREの解析はかなり複雑ですが、10秒は極端に思えます。気になる場合は、コード例を含めて質問し、専門家の意見を聞くことをお勧めします。
ghoti 2014年

非常に大きなhtmlファイルのソースを変数に保持していたため、私にとっては非常に遅いと思いました。コンテンツをファイルに書き込んでファイルを解析すると、速度が劇的に向上しました。
アダムジョンズ

22

GNU awkを通じて、

$ echo "Here is a string" | awk -v FS="(Here|string)" '{print $2}'
 is a 

-Pperl-regexp)パラメーターを指定したgrepは\K、以前に一致した文字を破棄するのに役立ちます。今回のケースでは、以前に一致した文字列がHere最終出力から破棄されたためです。

$ echo "Here is a string" | grep -oP 'Here\K.*(?=string)'
 is a 
$ echo "Here is a string" | grep -oP 'Here\K(?:(?!string).)*'
 is a 

出力にしたい場合はis a、以下を試すことができます、

$ echo "Here is a string" | grep -oP 'Here\s*\K.*(?=\s+string)'
is a
$ echo "Here is a string" | grep -oP 'Here\s*\K(?:(?!\s+string).)*'
is a

これは機能しません:echo "Here is a string dfdsf Here is a string" | awk -v FS="(Here|string)" '{print $2}'、@ Avinash Rajのis a代わりに返されるだけですis a is a
alper

20

複数行のオカレンスが多数ある長いファイルがある場合は、最初に番号行を印刷すると便利です。

cat -n file | sed -n '/Here/,/String/p'

3
ありがとう!これが私の場合に機能した唯一のソリューションです(改行のない単一の文字列ではなく、複数行のテキストファイル)。明らかに、行番号なしでそれを持つためには、-nオプションをcat省略しなければなりません。
Jeffrey Lebowski

...この場合cat、完全に省略できます。sedファイルまたは標準入力を読み取る方法を知っている。
tripleee 2017

9

これはあなたのために働くかもしれません(GNU sed):

sed '/Here/!d;s//&\n/;s/.*\n//;:a;/String/bb;$!{n;ba};:b;s//\n&/;P;D' file 

これは、改行の2つのマーカー(この例ではHereString)の間のテキストの各表現を示し、テキスト内の改行を保持します。


7

上記のすべてのソリューションには、最後の検索文字列が文字列の他の場所で繰り返されるという欠点があります。私はbash関数を書くのが一番いいと思いました。

    function str_str {
      local str
      str="${1#*${2}}"
      str="${str%%$3*}"
      echo -n "$str"
    }

    # test it ...
    mystr="this is a string"
    str_str "$mystr" "this " " string"

6

2つのsコマンドを使用できます

$ echo "Here is a String" | sed 's/.*Here//; s/String.*//'
 is a 

また働く

$ echo "Here is a StringHere is a String" | sed 's/.*Here//; s/String.*//'
 is a

$ echo "Here is a StringHere is a StringHere is a StringHere is a String" | sed 's/.*Here//; s/String.*//'
 is a 

6

sedコマンドを理解するには、ステップバイステップでコマンドを構築する必要があります。

これが元のテキストです

user@linux:~$ echo "Here is a String"
Here is a String
user@linux:~$ 

ubstitionオプションでHere文字列を削除してみましょうssed

user@linux:~$ echo "Here is a String" | sed 's/Here //'
is a String
user@linux:~$ 

この時点で、あなたStringも削除できると思います

user@linux:~$ echo "Here is a String" | sed 's/String//'
Here is a
user@linux:~$ 

しかし、これは望ましい出力ではありません。

2つのsedコマンドを組み合わせるには、-eオプションを使用します

user@linux:~$ echo "Here is a String" | sed -e 's/Here //' -e 's/String//'
is a
user@linux:~$ 

お役に立てれば


4

使用できます\1http://www.grymoire.com/Unix/Sed.html#uh-4参照):

echo "Hello is a String" | sed 's/Hello\(.*\)String/\1/g'

括弧内の内容はとして保存され\1ます。


これは、間に何かを出力する代わりに文字列を削除します。sedコマンドで「is」を使用して「Hello」を削除すると、「Hello a」が出力されます
Jonathan

1

問題。 保存されているClaws Mailメッセージは次のようにラップされており、件名行を抽出しようとしています。

Subject: [SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular
 link in major cell growth pathway: Findings point to new potential
 therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is
 Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as
 a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway
 identified [Lysosomal amino acid transporter SLC38A9 signals arginine
 sufficiency to mTORC1]]
Message-ID: <20171019190902.18741771@VictoriasJourney.com>

このスレッドのA2ごとに、sed / grepを使用して2つの単語間のテキストを抽出する方法は?以下の最初の式は、一致したテキストに改行が含まれていない限り「機能」します。

grep -o -P '(?<=Subject: ).*(?=molecular)' corpus/01

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key

ただし、多数のバリアント(.+?; /s; ...)を試しても、これらを機能させることができませんでした。

grep -o -P '(?<=Subject: ).*(?=link)' corpus/01
grep -o -P '(?<=Subject: ).*(?=therapeutic)' corpus/01
etc.

解決策1。

異なる行の2つの文字列間の抽出テキストごと

sed -n '/Subject: /{:a;N;/Message-ID:/!ba; s/\n/ /g; s/\s\s*/ /g; s/.*Subject: \|Message-ID:.*//g;p}' corpus/01

与える

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]                              

ソリューション2. *

あたりはどのようにsedを使って(\ n)は改行を置き換えることができますか?

sed ':a;N;$!ba;s/\n/ /g' corpus/01

改行をスペースに置き換えます。

2つの単語間のテキストを抽出するためにsed / grepを使用する方法の A2でそれを連鎖させますか?、 我々が得る:

sed ':a;N;$!ba;s/\n/ /g' corpus/01 | grep -o -P '(?<=Subject: ).*(?=Message-ID:)'

与える

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular  link in major cell growth pathway: Findings point to new potential  therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is  Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as  a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway  identified [Lysosomal amino acid transporter SLC38A9 signals arginine  sufficiency to mTORC1]] 

この亜種は二重スペースを削除します:

sed ':a;N;$!ba;s/\n/ /g; s/\s\s*/ /g' corpus/01 | grep -o -P '(?<=Subject: ).*(?=Message-ID:)'

与える

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.