find et écho des noms de file uniquement avec le model trouvé

Je l'ai beaucoup utilisé, l'amélioration que j'essaie d'accomplir est d'éviter les noms de files écho qui ne correspondaient pas dans grep. Meilleure façon de le faire?

for file in `find . -name "*.py"`; do echo $file; grep something $file; done 

 find . -name '*.py' -exec grep something {} \; -print 

imprimait le nom du file après les lignes correspondantes.

 find . -name '*.py' -exec grep something /dev/null {} + 

imprimerait le nom du file devant chaque ligne correspondante (nous ajoutons /dev/null pour le cas où il n'y a qu'un seul file correspondant car grep n'imprime pas le nom du file si un seul file est passé. grep a une option -H pour cela comme alternative).

 find . -name '*.py' -exec grep -l something {} + 

n'imprimerait que les noms de file des files qui ont au less une ligne correspondante.

Pour imprimer le nom du file 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 file – mais cela serait less efficace car il exécuterait au less une command grep et jusqu'à deux pour chaque file (et lit le contenu du file deux fois):

 find . -name '*.py' -exec grep -l something {} \; \ -exec grep something {} \; 

En tout cas, vous ne voulez pas boucler la sortie de find comme ça et n'oubliez pas de citer vos variables .

Si vous vouliez utiliser une boucle shell, avec les outils 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 {} + 

(fonctionne également sur FreeBSD et les dérivés).

Si vous utilisez GNU grep, vous pouvez utiliser son option -r ou --recursive pour effectuer cette simple search:

 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 si vous avez besoin de prédicats plus avancés.

Vous pouvez indiquer à grep d'inclure le nom de file 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 file, aucune ligne ne sera imprimée pour ce file.

 find . -name "*.py" | xargs grep -n -H something 

De l' 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 files peuvent avoir des noms contenant des espaces, vous devez basculer le tube pour utiliser les caractères NUL en tant que séparateur. La command complète va maintenant ressembler à ceci:

 find . -name "*.py" -print0 | xargs -0 grep -n -H something 

Vous pouvez essayer quelque chose comme:

 find . -name "*.py:" -exec grep -l {} \; 

Cette command exec grep pour chaque file, découverte par la command find et sa fonction de command de search standard

Utilisez l'argument -l .

 for file in `find . -name "*.py"`; do grep -l something $file && grep something $file; done 

Une utilisation plus findish serait:

 for file in $(find . -name '*.py' -exec grep -l something '{}' +); do echo "$file"; grep something $file; done 

Il existe des alternatives grep qui, par défaut, sortent leurs résultats dans le format que vous voulez. 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/xc 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 files dans un vert olive, les numéros de ligne en jaune d'or, et la pièce appariée dans chaque ligne en rouge sang. Les colors sont personnalisables cependant.