
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, us
y 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 clean
o 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 _raw
o _clean
despué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 grep
se haya creado con soporte PCRE), la expresión regular es compatible con Perl. En esas expresiones regulares, \K
restablece 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. -o
genera grep
la 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 _raw
o _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}'