Como extrair linhas se alguma das duas strings correspondentes corresponder?

Como extrair linhas se alguma das duas strings correspondentes corresponder?

Eu tenho um arquivo onde tenho algumas linhas de informações que contém o nome do país conforme mostrado abaixo.

$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

Quero extrair apenas os nomes dos países deste arquivo. Atualmente estou usando o código abaixo para extrair o nome do país em um loop for

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

Mas a saída produzida tem apenas nomes de países china, use au, portanto, tenho que repetir o código semelhante com pequenas modificações para extrair os países restantes, como abaixo

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

Esta não é uma forma clara de codificação, eu sei e, portanto, preciso da sua ajuda para extrair os nomes dos países de todas as linhas que contêm cleanou rawstring.

Existe uma maneira de usar awk ou sed para extrair todos os nomes de países com duas chaves de correspondência? Minha saída deve ficar assim

china
india
us
uk
canada
au

Responder1

Eu não usaria um shell loop para processar texto.

Aqui, você pode simplesmente fazer:

cut -d _ -f 2 < country.txt

Ou se a entrada puder conter linhas sem _caracteres:

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

Se o nome do país puder conter _caracteres e você quiser retornar a parte da linha entre a primeira _e a primeira ocorrência _rawou _cleandepois disso, você poderia fazer:

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

Ou com GNU grep:

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

Com -P(desde que greptenha sido construído com suporte PCRE), o regexp é compatível com Perl. Nessas regexps, \Kredefine o início da string correspondente e (?=...)é um operador lookahead, ou seja, verifica se o restante da string corresponde ...sem que essa parte seja incluída na parte correspondente. -ogera grepa saída da parte correspondente, então aqui ele imprime o que corresponde ao .*?acima, que é o equivalente não ganancioso de .*, que é uma sequência de 0 ou mais caracteres, o mais curto possível, neste caso seguindo uma sequência de 0 ou mais sublinhados ( [^_]*) encontrado no início da linha ( ^) seguido por um sublinhado e assumindo que seja seguido por _rawou _clean.

Com pcregrep, você também pode escrever:

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

Com -o1, ele imprime a parte correspondente ao primeiro (...).

Responder2

Aqui está o caminho no estilo awk

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

informação relacionada