2 つの一致文字列のいずれかが一致する場合に行を抽出するにはどうすればよいでしょうか?

2 つの一致文字列のいずれかが一致する場合に行を抽出するにはどうすればよいでしょうか?

以下に示すように、国名を含む数行の情報を含むファイルがあります。

$cat country.txt

max_china_clean_foo
man_india_raw_bar
max_us_clean_bax
max_uk_raw_bar
max_canada_raw_foo
max_au_clean_bar

このファイルから国名のみを抽出したいです。現在、forループで国名を抽出している以下のコードを使用しています。

val=${val#*_}
val=${val%_clean*}
echo $val

しかし、生成された出力には国名のみが含まれているため、以下のように残りの国を抽出するために、同様のコードを少し変更して繰り返す必要がありますchina, usau

val=${val#*_}
val=${val%_raw*}
echo $val

cleanこれは明確なコーディング方法ではないことは承知しています。そのため、または文字列が含まれるすべての行から国名を抽出するためにあなたの助けが必要ですraw

awk または sed を使用して、2 つの一致キーを持つすべての国名を抽出する方法はありますか? 出力は次のようになります。

china
india
us
uk
canada
au

答え1

テキスト処理にシェルループは使わない

ここでは、次の操作を実行できます。

cut -d _ -f 2 < country.txt

または、入力に_文字のない行が含まれる場合:

awk -F _ 'NF >= 2 {print $2}' < country.txt

国名に文字が含まれている可能性があり、代わりに最初の文字と最初の文字の間またはその後の_行の部分を返したい場合は、次のようにします。__raw_clean

perl -ne 'print $1 if s/^[^_]*_(.*?)_(clean|raw)/' < country.txt

あるいはGNUの場合grep:

grep -Po '^[^_]*_\K.*?(?=_clean|_raw)' < country.txt

を使用する場合-P( がgrepPCRE サポート付きでビルドされている場合)、正規表現は Perl 互換になります。これらの正規表現では、 は\K一致した文字列の先頭をリセットし、(?=...)は先読み演算子です...。つまり、一致した部分にその部分が含まれずに、文字列の残りの部分が一致するかどうかを検索します。 は一致した部分を出力-oします。そのため、ここでは と非貪欲に同等である上記にgrep一致するものを出力します。つまり、0 個以上の文字のシーケンスで、この場合は行の先頭()にある 0 個以上のアンダースコアのシーケンスの後にアンダースコアが続き、その後に または が続くものと想定します。.*?.*[^_]*^_raw_clean

を使用するとpcregrep、次のように書くこともできます。

pcregrep -o1 '^[^_]*_(.*?)_(clean|raw)'

を使用すると-o1、最初の に一致した部分が出力されます(...)

答え2

awkスタイルのやり方はこちら

awk -F'_' '/clean|raw/{ print $2}'

関連情報