Lo usé mucho, la mejora que intento lograr es evitar los nombres de archivos de eco que no coinciden en grep. ¿Mejor manera de hacer esto?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
Lo usé mucho, la mejora que intento lograr es evitar los nombres de archivos de eco que no coinciden en grep. ¿Mejor manera de hacer esto?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
Respuestas:
find . -name '*.py' -exec grep something {} \; -print
imprimiría el nombre del archivo después de las líneas coincidentes.
find . -name '*.py' -exec grep something /dev/null {} +
imprimiría el nombre del archivo delante de cada línea coincidente (agregamos /dev/null
para el caso donde solo hay un archivo coincidente, ya grep
que no imprime el nombre del archivo si se pasa solo un archivo para buscar. La implementación de GNU grep
tiene una -H
opción para eso como alternativa).
find . -name '*.py' -exec grep -l something {} +
imprimiría solo los nombres de los archivos que tienen al menos una línea coincidente.
Para imprimir el nombre del archivo antes de las líneas coincidentes, puede usar awk en su lugar:
find . -name '*.py' -exec awk '
FNR == 1 {filename_printed = 0}
/something/ {
if (!filename_printed) {
print FILENAME
filename_printed = 1
}
print
}' {} +
O llame grep
dos veces para cada archivo, aunque eso sería menos eficiente ya que ejecutaría al menos un grep
comando y hasta dos para cada archivo (y leería el contenido del archivo dos veces):
find . -name '*.py' -exec grep -l something {} \; \
-exec grep something {} \;
En cualquier caso, no desea recorrer la salida de find
ese tipo y recordar citar sus variables .
Si desea utilizar un bucle de shell, con herramientas GNU:
find . -name '*.py' -exec grep -l --null something {} + |
xargs -r0 sh -c '
for file do
printf "%s\n" "$file"
grep something < "$file"
done' sh
(también funciona en FreeBSD y derivados).
Si estás usando GNU grep, puede utilizar su -r
o --recursive
la opción de hacer este sencillo hallazgo para usted:
grep -r --include '*.py' -le "$regexp" ./ # for filenames only
grep -r --include '*.py' -He "$regexp" ./ # for filenames on each match
Solo necesita find
si necesita predicados más avanzados.
grep
, grep
puede o no mirar dentro de enlaces simbólicos o enlaces simbólicos transversales a directorios. También puede encontrar algunas variaciones en el manejo de otros tipos de archivos no regulares.
Puede decirle a grep que incluya el nombre del archivo en la salida. Entonces, si hay una coincidencia, se mostrará en la consola; Si no hay coincidencia dentro de un archivo, no se imprimirá ninguna línea para ese archivo.
find . -name "*.py" | xargs grep -n -H something
De la man grep
:
-H Always print filename headers with output lines
-n, --line-number
Each output line is preceded by its relative line number in the file, starting at line 1. The line number counter is reset for each file processed.
This option is ignored if -c, -L, -l, or -q is specified.
Si sus archivos pueden tener nombres con espacios en ellos, debe cambiar la tubería para usar caracteres NUL como separador. El comando completo ahora se verá así:
find . -name "*.py" -print0 | xargs -0 grep -n -H something
Puedes probar algo como:
find . -name "*.py:" -exec grep -l {} \;
Este comando exec grep para cada archivo, descubierto por el comando find y su función estándar de comando find
Hay grep
alternativas que, de forma predeterminada, generan sus resultados en el formato que desee. Los 2 la mayoría de los populares, que yo sepa son ag
(también conocido como "el buscador de plata") y ack
. ag
se anuncia como una alternativa más rápida a ack
.
$ ag '^\w+\s*\w+\(' ~/build/i3/src
build/i3/src/display_version.c
58:void display_running_version(void) {
build/i3/src/load_layout.c
42:static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings =
518:json_content_t json_determine_content(const char *filename) {
575:void tree_append_json(Con *con, const char *filename, char **errormsg) {
build/i3/src/x.c
64:CIRCLEQ_HEAD(state_head, con_state) state_head =
67:CIRCLEQ_HEAD(old_state_head, con_state) old_state_head =
70:TAILQ_HEAD(initial_mapping_head, con_state) initial_mapping_head =
97:void x_con_init(Con *con, uint16_t depth) {
...
No puedo mostrarte aquí, pero la salida está perfectamente coloreada. Obtengo los nombres de archivo en un verde oliva, los números de línea en amarillo dorado y la pieza coincidente en cada línea en rojo sangre. Sin embargo, los colores son personalizables.