A veces (en casos simples) es posible ajustar el separador de campo ( FS) y elegir lo que a uno le gustaría combinar con a $field. Preformatear la entrada también podría ayudar.
Al parecer, alguien no está de acuerdo. Esta página web es de 2005: tek-tips.com/faqs.cfm?fid=5674 Confirma que no puede reutilizar grupos coincidentes en awk.
Peter Tillemans
3
Prefiero 'perl -n -p -e ...' sobre awk para casi todos los casos de uso, ya que es más flexible, más potente y tiene una sintaxis más sensata en mi opinión.
Peter Tillemans
15
gawk! = awk. Son herramientas diferentes y gawkno están disponibles por defecto en la mayoría de los lugares.
Oli
66
El OP solicitó específicamente una solución awk, por lo que no creo que sea una respuesta.
Joppe
66
@Joppe, no puedes dar una solución awk si no hay solución. En la línea 3 explico que AWK no admite la captura de grupos y di una alternativa, que el OP aparentemente apreció porque esta respuesta fue aceptada. ¿Cómo podría responder mejor esta pregunta?
Peter Tillemans
335
Con gawk, puede usar la matchfunción para capturar grupos entre paréntesis.
gawk 'match($0, pattern, ary) {print ary[1]}'
ejemplo:
echo "abcdef"| gawk 'match($0, /b(.*)e/, a) {print a[1]}'
salidas cd.
Tenga en cuenta el uso específico de gawk que implementa la función en cuestión.
Para una alternativa portátil, puede lograr resultados similares con match()y substr.
Ed Morton: eso merece una respuesta de alto nivel, diría. edit: uhm ... eso imprime RewriteRule (.*) http://www.mysite.net/$para mí, que es más que el subgrupo.
También puede simular la captura en vainilla awk, sin extensiones. Sin embargo, no es intuitivo:
paso 1. usa gensub para rodear coincidencias con algún carácter que no aparece en tu cadena. paso 2. Utiliza split contra el personaje. paso 3. Cualquier otro elemento en la matriz dividida es tu grupo de captura.
$ echo 'ab cb ad' | awk '{split (gensub (/ a ./, SUBSEP "y" SUBSEP, "g", $ 0), cap, SUBSEP); gorra de impresión [2] "|" gorra [4]; } '
ab | ad
Estoy casi seguro de que gensubes una gawkfunción específica. ¿Qué obtienes de tu awk si escribes awk --version; -?). Buena suerte a todos.
shellter
66
Estoy completamente seguro de que gensub es un gawk-ism, aunque BusyBox awk también lo tiene. Sin embargo, esta respuesta también podría implementarse usando gsub:echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
dubiousjim
3
gensub () es una extensión de gawk, el manual de gawk lo dice claramente. Otras variantes de awk también pueden implementarlo, pero todavía no es POSIX. Prueba gawk --posix '{gsub (...)}' y se quejará
MestreLion
2
@MestreLion, quieres decir que se quejará gawk --posix '{gensub(...)}'.
dubiousjim
1
A pesar de que estaba equivocado acerca de que POSIX awk tenía la gensubfunción, su ejemplo se aplicó a un escenario muy limitado: todo el patrón está agrupado, no puede coincidir con algo como todo key=(value)cuando quiero extraer solo las valuepartes.
Miau
2
Me costó un poco encontrar una función bash que envuelva la respuesta de Peter Tillemans, pero esto es lo que se me ocurrió:
función regex {perl -n -e "/ $ 1 / && printf \"% s \ n \ "," '$ 1'}
Encontré que esto funcionó mejor que la función bash basada en awk de opsb para el siguiente argumento de expresión regular, porque no quiero que se imprima el "ms".
Prefiero esta solución, ya que puede ver las partes del grupo que delimitan la captura, al tiempo que las omite. Sin embargo, ¿podría alguien explicar cómo funciona esto? No puedo hacer que esta sintaxis de Perl funcione correctamente en BASH, porque no lo entiendo muy bien, especialmente las comillas dobles / simples alrededor$1
Demis
No es algo que haya hecho antes o desde entonces, pero mirar hacia atrás lo que está haciendo es concatenar dos cadenas, la primera cadena entre comillas dobles (esta primera cadena contiene comillas dobles incrustadas con barra invertida) y la segunda cadena entre comillas simples. . Luego, el resultado de esa concatenación se proporciona como argumento para perl -e. También debe saber que el primer $ 1 (el que está entre comillas dobles) se sustituye con el primer argumento de la función, mientras que el segundo $ 1 (el que está entre comillas simples) no se toca. Ver este ejemplo
wytten el
Ya veo, eso tiene un poco más de sentido ahora. Entonces, ¿en qué parte del comando perl está la definición de captura de expresiones / grupos de expresiones regulares? Veo que escribiste '([0-9]*)ms$': ¿se proporciona como argumento (y la cadena es otro argumento)? Y la salida de perl -ese está insertando en el printfcomando de bash entonces, para reemplazar %s, ¿es correcto? Gracias, espero usar esto.
Demis
1
Pasa una expresión regular encerrada entre comillas simples como único argumento para la función regex bash. Ejemplo
FS
) y elegir lo que a uno le gustaría combinar con a$field
. Preformatear la entrada también podría ayudar.gawk
(ya que usagensub
).Respuestas:
Ese fue un paseo por el carril de la memoria ...
Reemplacé awk por perl hace mucho tiempo.
Aparentemente, el motor de expresión regular AWK no captura sus grupos.
podrías considerar usar algo como:
la bandera -n hace que perl recorra cada línea como lo hace awk.
fuente
gawk
! =awk
. Son herramientas diferentes ygawk
no están disponibles por defecto en la mayoría de los lugares.Con gawk, puede usar la
match
función para capturar grupos entre paréntesis.ejemplo:
salidas
cd
.Tenga en cuenta el uso específico de gawk que implementa la función en cuestión.
Para una alternativa portátil, puede lograr resultados similares con
match()
ysubstr
.ejemplo:
salidas
cd
.fuente
Esto es algo que necesito todo el tiempo, así que creé una función bash para ello. Se basa en la respuesta de Glenn Jackman.
Definición
Agregue esto a su .bash_profile, etc.
Uso
Capture expresiones regulares para cada línea en el archivo
Capture el primer grupo de captura de expresiones regulares para cada línea en el archivo
fuente
grep -o
?grep -o
generar grupos capturados?grep -o
.Puedes usar GNU awk:
fuente
awk 'match($0, /.*(http.*?)\$/) { print substr($0,RSTART,RLENGTH) }'
RewriteRule (.*) http://www.mysite.net/$
para mí, que es más que el subgrupo.RSTART
y seRLENGTH
refiere a la subcadena combinada con el patrónTambién puede simular la captura en vainilla awk, sin extensiones. Sin embargo, no es intuitivo:
paso 1. usa gensub para rodear coincidencias con algún carácter que no aparece en tu cadena. paso 2. Utiliza split contra el personaje. paso 3. Cualquier otro elemento en la matriz dividida es tu grupo de captura.
fuente
gensub
es unagawk
función específica. ¿Qué obtienes de tu awk si escribesawk --version
; -?). Buena suerte a todos.echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
gawk --posix '{gensub(...)}'
.gensub
función, su ejemplo se aplicó a un escenario muy limitado: todo el patrón está agrupado, no puede coincidir con algo como todokey=(value)
cuando quiero extraer solo lasvalue
partes.Me costó un poco encontrar una función bash que envuelva la respuesta de Peter Tillemans, pero esto es lo que se me ocurrió:
Encontré que esto funcionó mejor que la función bash basada en awk de opsb para el siguiente argumento de expresión regular, porque no quiero que se imprima el "ms".
fuente
$1
'([0-9]*)ms$'
: ¿se proporciona como argumento (y la cadena es otro argumento)? Y la salida deperl -e
se está insertando en elprintf
comando de bash entonces, para reemplazar%s
, ¿es correcto? Gracias, espero usar esto.