
Pregunta 1
Puedo usar
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' /etc/rc.d/init.d/functions
para obtener un resultado como el siguiente:
systemctl_redirect ()
checkpid()
__kill_pids_term_kill_checkpids()
__kill_pids_term_kill()
__pids_var_run()
__pids_pidof()
daemon()
killproc()
pidfileofproc()
pidofproc()
status()
echo_success()
echo_failure()
echo_passed()
echo_warning()
update_boot_stage()
success()
failure()
passed()
warning()
action()
strstr()
is_ignored_file()
is_true()
is_false()
apply_sysctl()
Y también quiero saber cuántas apariciones han coincidido, así que uso -c
la opción, esta vez solo obtengo 26
, ¿puedo combinar contenidos coincidentes y recuentos congrep
incorporadoopciones? Si no, ¿cómo?
Pregunta 2
Encontré una solución en Github para responder la Pregunta 1:
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' /etc/rc.d/init.d/functions \
| tee >(echo -e "\n`wc -l` matched.")
Pero el resultado suele ser extraño, ya que se genera después de una nuevaindicador de shell!¿Por qué?
Respuesta1
Siempre puedes hacer:
grep -o ... | awk '{print};END{if (NR) print "\n" NR " matched."}'
O hacer todo en awk
(lo que también evitaría los GNUismos -o
y \+
):
awk 'match($0, /^[[:alpha:]_]+[[:blank:]]*\([[:blank:]]*\)/) {
print substr($0, RSTART, RLENGTH)
n++
}
END{if (n) print "\n" n " matched.")'
o perl
:
perl -lne 'for (/^\w+\h*\(\h*\)/g) {print; $n++}
END {print "\n$n matched." if $n}'
(tenga en cuenta que en ese caso \w
está limitado a letras ASCII, agregue a -Mopen=locale
para incluir cualquier letra en cualquier escritura alfabética según la configuración regional, como en los enfoques grep
o awk
(algunos awk
))
Acerca de su pregunta 2, eso se debe a que bash
(a diferencia de zsh
) no espera a que se inicien los comandos en la sustitución del proceso, lo que causa este tipo de problema. VerLa salida de sustitución del proceso está fuera de orden.para más detalles.
Respuesta2
En lugar de tee
utilizar una herramienta comopee
:
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' /etc/rc.d/init.d/functions |
pee cat 'sleep 1; echo -e "\n`wc -l` matched."'
Si pee
no está disponible, se puede hacer con un bash
shell separado y silenciar sus indicaciones con unset
y shopt
:
bash -c \
"unset PS0 PS1 PS2 PS3
shopt -u promptvars
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' \
/etc/rc.d/init.d/functions |
tee >( sleep 1s; printf '\n%s matched.' `wc -l`; )
sleep 2s"
Respuestas generales:
No se puede hacer con una sola instancia de
grep
.Para obtener un recuento completo cuando hay más de una coincidencia por línea
grep -o
, utilicewc -l
:printf "foo bar baz\nbuz biz\n" | grep -o 'b[^ ]*' | wc -l
Producción:
4
Si se necesita un recuento con prefijo, utilice
nl
, (ocat -n
):printf "foo bar baz\nbuz biz\n" | grep -o 'b[^ ]*' | nl
Producción:
1 bar 2 baz 3 buz 4 biz
Con procesos paralelos,es decir
tee >(echo -e "\n`wc -l` matched.")
No hay garantía de qué proceso finaliza primero. A veces se puede añadir un pequeño retraso para asegurar el pedido.
Imprimir paralelo "foo" primero luego "uf"después de un retraso de 1 segundo:
echo foo | tee >(sleep 1s; rev)
Imprimir paralelo "uf" primero luego "foo"después de un retraso de 1 segundo:
echo foo | tee >(rev) >(sleep 1s;cat) > /dev/null