0

I have a file where I have few lines of information that contains the country name as shown below.

$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

I want to extract only the country names from this file. I am currently using the below code to extract country name in a for loop

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

But the output produced has only china, us and au country names and hence I have to repeat the similar code with minor modifications to extract the remaining countries like below

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

This is not a clear way of coding, I know and hence need your help to extract the country names from all the lines that has either clean or raw string in it.

Is there a way using awk or sed to extract all the country names with two match keys? My output should look like this

china
india
us
uk
canada
au
2

I wouldn't use a shell loop to process text.

Here, you can just do:

cut -d _ -f 2 < country.txt

Or if the input may contain lines without _ characters:

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

If the country name may contain _ character and you want instead to return the part of the line in between the first _ and the first occurrence of _raw or _clean after that, you could do:

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

Or with GNU grep:

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

With -P (provided grep has been built with PCRE support), the regexp is a perl-compatible one. In those regexps, \K resets the start of the matched string, and (?=...) is a look-ahead operator, that is it looks if the rest of the string matches ... without that part being included in the matched portion. -o makes grep output the matched portion, so here it prints what matches the .*? above which is the non-greedy equivalent of .*, that is a sequence of 0 or more characters, as short as possible, in this case following a sequence of 0 or more underscores ([^_]*) found at the start of the line (^) followed by an underscore and assuming it's followed by either _raw or _clean.

With pcregrep, you can also write it:

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

With -o1, it prints the portion matched by the first (...).

  • Thanks for your answer. Could you please explain the grep command? – Alex Raj Kaliamoorthy Oct 4 '16 at 7:14
0

Here is the way in awk style

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.