
У меня есть файл, в котором есть несколько строк информации, содержащей название страны, как показано ниже.
$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}'