web-dev-qa-db-ja.com

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

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

入力:

"Here is a String"

出力:

"is a"

使用方法

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

エンドポイントを含みますが、それらは含めたくありません。

101
user1190650
sed -e 's/Here\(.*\)String/\1/'
84
Brian Campbell

GNU grepは、ポジティブ&ネガティブルックアヘッド&ルックバックもサポートします。あなたの場合、コマンドは次のようになります。

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

Herestringが複数回出現する場合は、最初の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 
143
anishsane

承認された回答では、Hereの前またはStringの後のテキストは削除されません。この意志:

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

主な違いは、Hereの直前とStringの直後に.*を追加したことです。

41
wheeler

Bash だけで文字列を削除できます。

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

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

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

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
20
Avinash Raj

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

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

これはうまくいくかもしれません(GNU sed)。

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

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

8
potong

上記のすべての解決策には、最後の検索文字列が文字列の別の場所で繰り返されるという欠点があります。 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"
5
Gary Dean

\1を使うことができます( http://www.grymoire.com/Unix/Sed.html#uh-4 を参照してください)。

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

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

3
mvairavan

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

これがあなたの元のテキストです。

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

Heresubstitionオプションでsedを削除してみましょう

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:~$ 

お役に立てれば

2
Sabrina

問題私の保存したClaws Mailメッセージは以下のようにラップされていて、Subject行を抽出しようとしています。

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: <[email protected]>

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

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

Per 異なる行にある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。*

Per sedを使って改行(\ n)を置き換えるにはどうすればいいですか?

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

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

でA2を使ってそれをチェーニングする2つの単語の間のテキストを抽出するためにsed/grepを使用する方法? 、 我々が得る:

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]]
0
Victoria Stuart