Как извлечь строки, если хотя бы одна из двух строк соответствия совпадает?

Как извлечь строки, если хотя бы одна из двух строк соответствия совпадает?

У меня есть файл, в котором есть несколько строк информации, содержащей название страны, как показано ниже.

$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, usназвания auстран, поэтому мне приходится повторять аналогичный код с небольшими изменениями, чтобы извлечь оставшиеся страны, как показано ниже.

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

Я знаю, что это не совсем понятный способ кодирования, и поэтому мне нужна ваша помощь, чтобы извлечь названия стран из всех строк, содержащих строку cleanили raw.

Есть ли способ, используя awk или sed, извлечь все названия стран с двумя ключами совпадения? Мой вывод должен выглядеть так

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(при условии, что grepбыл построен с поддержкой PCRE), регулярное выражение является совместимым с Perl. В этих регулярных выражениях \Kсбрасывает начало совпавшей строки и (?=...)является оператором просмотра вперед, то есть он проверяет, совпадает ли остальная часть строки ...без включения этой части в совпавшую часть. -oвыводит grepсовпавшую часть, поэтому здесь он печатает то, что соответствует .*?указанному выше, что является нежадным эквивалентом .*, то есть последовательность из 0 или более символов, как можно короче, в данном случае после последовательности из 0 или более символов подчеркивания ( [^_]*), найденных в начале строки ( ^), за которой следует подчеркивание, и предполагается, что за ним следует либо , _rawлибо _clean.

С помощью pcregrepвы также можете написать это:

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

При использовании -o1он выводит часть, соответствующую первой (...).

решение2

Вот как это сделать в стиле awk

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

Связанный контент