Digamos que tengo un archivo:
# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar
Solo quiero saber qué palabras aparecen después de "foobar", para poder usar esta expresión regular:
"foobar \(\w\+\)"
El paréntesis indica que tengo un interés especial en la palabra justo después de foobar. Pero cuando hago un grep "foobar \(\w\+\)" test.txt
, obtengo las líneas completas que coinciden con la expresión regular completa, en lugar de solo "la palabra después de foobar":
foobar bash 1
foobar happy
Preferiría mucho que la salida de ese comando se viera así:
bash
happy
¿Hay alguna manera de decirle a grep que solo muestre los elementos que coinciden con la agrupación (o una agrupación específica) en una expresión regular?
text-processing
grep
regular-expression
Cory Klein
fuente
fuente
perl -lne 'print $1 if /foobar (\w+)/' < test.txt
Respuestas:
GNU grep tiene la
-P
opción de expresiones regulares de estilo perl, y la-o
opción de imprimir solo lo que coincida con el patrón. Estos se pueden combinar usando aserciones de mirar alrededor (descritas en Patrones extendidos en la página de manual de perlre ) para eliminar parte del patrón grep de lo que se determina que coincide con el propósito de-o
.Esta
\K
es la forma abreviada (y una forma más eficiente)(?<=pattern)
que utiliza como una afirmación de retrospectiva de ancho cero antes del texto que desea generar.(?=pattern)
se puede usar como una aserción anticipada de ancho cero después del texto que desea generar.Por ejemplo, si desea hacer coincidir la palabra entre
foo
ybar
, puede usar:o (por simetría)
fuente
sed(1)
grep -oP 'foobar \K\w+' test.txt
no genera nada con los OPtest.txt
. La versión grep es 2.5.1. Qué podría estar mal ? O_OGrep estándar no puede hacer esto, pero las versiones recientes de GNU grep sí . Puedes recurrir a sed, awk o perl. Aquí hay algunos ejemplos que hacen lo que desea en su entrada de muestra; se comportan de manera ligeramente diferente en los casos de esquina.
Reemplace
foobar word other stuff
porword
, imprima solo si se realiza un reemplazo.Si la primera palabra es
foobar
, imprima la segunda palabra.Tira
foobar
si es la primera palabra, y salta la línea de lo contrario; luego elimine todo después del primer espacio en blanco e imprima.fuente
grep
. Pero la sintaxis para estos comandos en realidad parece muy familiar ahora que estoy familiarizado con la búsqueda y reemplazo + expresiones regulares de estilo vim. Gracias una tonelada.grep
no tiene soporte PCRE.fuente
^
y$
son extraños ya que.*
es un partido codicioso. Sin embargo, incluirlos podría ayudar a aclarar la intención de la expresión regular.Bueno, si sabes que foobar es siempre la primera palabra o la línea, entonces puedes usar cortar. Al igual que:
fuente
-o
cambio en grep está ampliamente implementado (más que las extensiones grep de Gnu), por logrep -o "foobar" test.file | cut -d" " -f2
que aumentará la efectividad de esta solución, que es más portátil que el uso de afirmaciones retrospectivas.grep -o "foobar .*
"ogrep -o "foobar \w+"
.Si PCRE no es compatible, puede lograr el mismo resultado con dos invocaciones de grep. Por ejemplo, para agarrar la palabra después de foobar, haga esto:
Esto se puede expandir a una palabra arbitraria después de foobar como esta (con ERE para facilitar la lectura):
Salida:
Tenga en cuenta que el índice
i
está basado en cero.fuente
pcregrep
tiene una-o
opción más inteligente que le permite elegir qué grupos de captura desea obtener. Entonces, usando su archivo de ejemplo,fuente
El uso
grep
no es compatible con plataformas cruzadas, ya que-P
/--perl-regexp
solo está disponible en GNUgrep
, no en BSDgrep
.Aquí está la solución usando
ripgrep
:Según
man rg
:Relacionado: GH-462 .
fuente
La respuesta de @jgshawkey me pareció muy útil.
grep
no es una herramienta tan buena para esto, pero sed lo es, aunque aquí tenemos un ejemplo que usa grep para tomar una línea relevante.La sintaxis de expresiones regulares de sed es idiosincrásica si no está acostumbrado.
Aquí hay otro ejemplo: este analiza la salida de xinput para obtener un número entero ID
y quiero 19
Tenga en cuenta la sintaxis de la clase:
y la necesidad de escapar de lo siguiente
+
Supongo que solo una línea coincide.
fuente
grep
, asumiendo que 'TouchPad' está a la izquierda de 'id':echo "SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]" | sed -nE "s/.*TouchPad.+id=([0-9]+).*/\1/p"