¿Cómo extraer líneas si alguna de las dos cadenas coincidentes?

¿Cómo extraer líneas si alguna de las dos cadenas coincidentes?

Tengo un archivo donde tengo algunas líneas de información que contiene el nombre del país como se muestra a continuación.

$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

Quiero extraer sólo los nombres de los países de este archivo. Actualmente estoy usando el siguiente código para extraer el nombre del país en un bucle for.

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

Pero el resultado producido solo tiene nombres de países china, usy au, por lo tanto, tengo que repetir el código similar con modificaciones menores para extraer los países restantes como se muestra a continuación.

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

Esta no es una forma clara de codificar, lo sé y, por lo tanto, necesito su ayuda para extraer los nombres de los países de todas las líneas que contienen una cadena cleano raw.

¿Hay alguna forma de utilizar awk o sed para extraer todos los nombres de países con dos claves coincidentes? Mi salida debería verse así

china
india
us
uk
canada
au

Respuesta1

No usaría un bucle de shell para procesar texto.

Aquí, puedes simplemente hacer:

cut -d _ -f 2 < country.txt

O si la entrada puede contener líneas sin _caracteres:

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

Si el nombre del país puede contener _caracteres y, en cambio, desea devolver la parte de la línea entre la primera _y la primera aparición de _rawo _cleandespués de eso, puede hacer:

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

O con GNU grep:

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

Con -P(siempre que grepse haya creado con soporte PCRE), la expresión regular es compatible con Perl. En esas expresiones regulares, \Krestablece el inicio de la cadena coincidente y (?=...)es un operador de anticipación, es decir, busca si el resto de la cadena coincide ...sin que esa parte se incluya en la parte coincidente. -ogenera grepla parte coincidente, por lo que aquí imprime lo que coincide con lo .*?anterior, que es el equivalente no codicioso de .*, es decir, una secuencia de 0 o más caracteres, lo más corta posible, en este caso siguiendo una secuencia de 0 o más guiones bajos ( [^_]*) que se encuentra al inicio de la línea ( ^) seguido de un guión bajo y suponiendo que vaya seguido de _rawo _clean.

Con pcregrep, también puedes escribirlo:

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

Con -o1, imprime la porción que coincide con la primera (...).

Respuesta2

Aquí está el camino en estilo awk.

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

información relacionada