J'ai beaucoup utilisé cela, l'amélioration que j'essaie de réaliser est d'éviter les noms de fichiers échos qui ne correspondent pas à grep. Une meilleure façon de procéder?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
find . -name '*.py' -exec grep something {} \; -print
afficherait le nom du fichier après les lignes correspondantes.
find . -name '*.py' -exec grep something /dev/null {} +
afficherait le nom du fichier devant chaque ligne correspondante (nous ajoutons /dev/null
pour le cas où il n'y a qu'un un fichier correspondant comme grep
n'imprime pas le nom du fichier s'il n'est transmis qu'à un seul fichier regardez dans. L'implémentation GNU de grep
a un -H
option pour cela comme alternative).
find . -name '*.py' -exec grep -l something {} +
afficherait uniquement les noms de fichier des fichiers qui ont au moins une ligne correspondante.
Pour imprimer le nom du fichier avant les lignes correspondantes, vous pouvez utiliser awk à la place:
find . -name '*.py' -exec awk '
FNR == 1 {filename_printed = 0}
/something/ {
if (!filename_printed) {
print FILENAME
filename_printed = 1
}
print
}' {} +
Ou appelez grep
deux fois pour chaque fichier - mais ce serait moins efficace car il exécuterait au moins une commande grep
et jusqu'à deux pour chaque fichier (et lirait le contenu du fichier deux fois ):
find . -name '*.py' -exec grep -l something {} \; \
-exec grep something {} \;
Dans tous les cas, vous ne voulez pas faire une boucle sur la sortie de find
comme ça et n'oubliez pas de citer vos variables .
Si vous vouliez utiliser une boucle Shell, avec GNU tools:
find . -name '*.py' -exec grep -l --null something {} + |
xargs -r0 sh -c '
for file do
printf "%s\n" "$file"
grep something < "$file"
done' sh
(fonctionne également sur FreeBSD et ses dérivés).
Si vous utilisez GNU grep, vous pouvez utiliser son -r
ou --recursive
option pour faire cette recherche simple pour vous:
grep -r --include '*.py' -le "$regexp" ./ # for filenames only
grep -r --include '*.py' -He "$regexp" ./ # for filenames on each match
Vous n'avez besoin de find
que si vous avez besoin de prédicats plus avancés.
Vous pouvez dire à grep d'inclure le nom de fichier dans la sortie. Donc, s'il y a une correspondance, elle sera affichée sur la console; s'il n'y a pas de correspondance dans un fichier, aucune ligne ne sera imprimée pour ce fichier.
find . -name "*.py" | xargs grep -n -H something
Du 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 vos fichiers peuvent avoir des noms avec des espaces, vous devez changer le canal pour utiliser des caractères NUL comme séparateur. La commande complète ressemblera maintenant à ceci:
find . -name "*.py" -print0 | xargs -0 grep -n -H something
Utilisez le -l
argument.
for file in `find . -name "*.py"`; do grep -l something $file && grep something $file; done
Une utilisation plus trouvaille serait:
for file in $(find . -name '*.py' -exec grep -l something '{}' +); do echo "$file"; grep something $file; done
Il existe grep
alternatives qui, par défaut, produisent leurs résultats au format souhaité. Les 2 plus populaires que je connais sont ag
(alias "le chercheur d'argent") et ack
. ag
est annoncé comme une alternative plus rapide à 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) {
...
Je ne peux pas vous montrer ici, mais la sortie est bien colorée. Je reçois les noms de fichiers en vert olive, les numéros de ligne en jaune doré et la pièce assortie de chaque ligne en rouge sang. Les couleurs sont cependant personnalisables.
Vous pouvez essayer quelque chose comme:
find . -name "*.py:" -exec grep -l {} \;
Cette commande exec grep pour chaque fichier, découverte par la commande find et sa fonction de commande find standard