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 Answers 2

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 (...).

1
  • Thanks for your answer. Could you please explain the grep command? Commented Oct 4, 2016 at 7:14
0

Here is the way in awk style

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .