web-dev-qa-db-fra.com

recherche et écho des noms de fichiers uniquement avec un motif trouvé

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
17
Gang
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).

25
Stéphane Chazelas

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.

6
Toby Speight

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
5
rollstuhlfahrer

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
1
kmkaplan

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.

1
JoL

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

1
Romeo Ninov