Veo muchos ejemplos y páginas de manual sobre cómo hacer cosas como buscar y reemplazar usando sed, awk o gawk.
Pero en mi caso, tengo una expresión regular que quiero ejecutar en un archivo de texto para extraer un valor específico. No quiero buscar y reemplazar. Esto se llama desde bash. Usemos un ejemplo:
Ejemplo de expresión regular:
.*abc([0-9]+)xyz.*
Archivo de entrada de ejemplo:
a
b
c
abc12345xyz
a
b
c
Tan simple como suena, no puedo entender cómo llamar a sed / awk / gawk correctamente. Lo que esperaba hacer es que mi script bash tenga:
myvalue=$( sed <...something...> input.txt )
Las cosas que he probado incluyen:
sed -e 's/.*([0-9]).*/\\1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/\\1/g' example.txt # extracts nothing
Respuestas:
Mi
sed
(Mac OS X) no funcionó con+
. Intenté en su*
lugar y agregué unap
etiqueta para imprimir coincidencia:Para hacer coincidir al menos un carácter numérico sin
+
, usaría:fuente
+
y luego funcionó para mí:sed -n 's/^.*abc\([0-9]\+\)xyz.*$/\1/p'
Puedes usar sed para hacer esto
-n
no imprima la línea resultante-r
esto hace que no tenga el escape del grupo de captura parens()
.\1
el partido del grupo de captura/g
partido global/p
imprimir el resultadoEscribí una herramienta para mí que lo hace más fácil.
fuente
Utilizo
perl
para hacer esto más fácil para mí. p.ejEsto ejecuta Perl, la
-n
opción le indica a Perl que lea en una línea a la vez desde STDIN y ejecute el código. La-e
opción especifica la instrucción a ejecutar.La instrucción ejecuta una expresión regular en la línea leída y, si coincide, imprime el contenido del primer conjunto de corchetes (
$1
).También puede hacer esto con varios nombres de archivo al final. p.ej
perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt
fuente
Si su versión de lo
grep
admite, puede usar la-o
opción para imprimir solo la parte de cualquier línea que coincida con su expresión regular.Si no es así, aquí está lo mejor
sed
que se me ocurrió:... que elimina / omite sin dígitos y, para las líneas restantes, elimina todos los caracteres iniciales y finales que no son dígitos. (Solo supongo que su intención es extraer el número de cada línea que contiene uno).
El problema con algo como:
.... o
... es que
sed
solo admite coincidencias "codiciosas" ... por lo que el primero. * coincidirá con el resto de la línea. A menos que podamos usar una clase de carácter negada para lograr una coincidencia no codiciosa ... o una versiónsed
compatible con Perl u otras extensiones para sus expresiones regulares, no podemos extraer una coincidencia de patrón precisa con el espacio de patrón (una línea ).fuente
sed
comandos de esta manera:sed -n 's/[^0-9]*\([0-9]\+\).*/\1/p'
grep -o
! Estaba tratando de hacer estosed
y luché con mi necesidad de encontrar múltiples coincidencias en algunas líneas. Mi solución es stackoverflow.com/a/58308239/117471Puede utilizar
awk
conmatch()
para acceder al grupo capturado:Esto intenta coincidir con el patrón
abc[0-9]+xyz
. Si lo hace, almacena sus cortes en la matrizmatches
, cuyo primer elemento es el bloque[0-9]+
. Dado quematch()
devuelve la posición del carácter, o índice, de donde comienza esa subcadena (1, si comienza al principio de la cadena) , activa laprint
acción.Con
grep
puede utilizar una mirada hacia atrás y hacia adelante:Esto comprueba el patrón
[0-9]+
cuando se produce dentroabc
yxyz
ya sólo imprime los dígitos.fuente
perl es la sintaxis más limpia, pero si no tiene perl (no siempre está ahí, según tengo entendido), entonces la única forma de usar gawk y los componentes de una expresión regular es usar la función gensub.
la salida del archivo de entrada de muestra será
Nota: gensub reemplaza toda la expresión regular (entre //), por lo que debe colocar. * Antes y después de ([0-9] +) para eliminar el texto antes y después del número en la sustitución.
fuente
match()
para acceder a los grupos capturados. Vea mi respuesta para esto.Si desea seleccionar líneas, elimine los bits que no desea:
Básicamente, selecciona las líneas que desea
egrep
y luego las usased
para quitar los bits antes y después del número.Puedes ver esto en acción aquí:
Actualización: obviamente, si su situación real es más compleja, los RE necesitarán modificarlos. Por ejemplo, si siempre tuvo un solo número enterrado dentro de cero o más números no numéricos al principio y al final:
fuente
El caso del OP no especifica que puede haber múltiples coincidencias en una sola línea, pero para el tráfico de Google, también agregaré un ejemplo para eso.
Dado que la necesidad del OP es extraer un grupo de un patrón, el uso
grep -o
requerirá 2 pasadas. Pero, todavía encuentro que esta es la forma más intuitiva de hacer el trabajo.Dado que el tiempo del procesador es básicamente gratuito, pero la legibilidad humana no tiene precio, tiendo a refactorizar mi código en función de la pregunta, "dentro de un año, ¿qué voy a pensar que hace esto?" De hecho, para el código que tengo la intención de compartir públicamente o con mi equipo, incluso abriré
man grep
para averiguar cuáles son las opciones largas y sustituirlas. Al igual que:grep --only-matching --extended-regexp
fuente
puedes hacerlo con el caparazón
fuente
Por awk. Usaría el siguiente script:
fuente
([0-9+])
genera el valor numérico , esto genera la línea completa.fuente