Tuyauterie d'une découverte vers grep

8

Qu'est-ce que j'essaye de faire?

Écrivez une commande qui recherche les fichiers qui ne sont requis par aucun autre fichier de mon projet.

Qu'est-ce que j'ai essayé?

J'utilise findpour obtenir une liste des noms de fichiers. Maintenant, je veux utiliser les noms de fichiers comme chaîne de recherche (plutôt que le fichier à rechercher).

J'utilise find server/lib -type f -exec basename {} \; | cut -f 1 -d '.'pour obtenir ma liste de noms de fichiers et supprimer l'extension de fichier.

Maintenant, je sais que c'est dans ce grep -R --exclude-dir=node_modules <search-string> . -lque je veux diriger chaque nom de fichier, mais je ne sais pas comment les passer comme <search-string>argument.


Autre info

Je suis aussi vaguement conscient que la tuyauterie vers cela greppourrait passer tout le résultat de find(la liste complète des fichiers) que je ne veux évidemment pas faire si c'est ce que je suis sur le point de me dire.

De plus, (bien que cela ne soit probablement pas dans le cadre de cette question) car j'utilise cela comme un moyen de trouver l'un des noms de fichiers qui grepne trouve rien pour quoi que ce soit, tout conseil sur l'obtention de ce type de sortie serait grandement apprécié

> <the-command>

filename1
server/lib/foo.js # where these are the list of files in which it appears
test/lib/foo.js

filename2
Not Found! #where `filename2` wasn't found anywhere (obviously)
Simon Legg
la source

Réponses:

2

Réponse courte:

Si vous voulez simplement passer un tas de lignes comme arguments à une autre commande, xargsc'est votre ami - dans ce cas, parce que vous le placez au milieu d'une commande, vous voudrez utiliser l' -I {}indicateur. Cela se définit {}comme un espace réservé afin que vous puissiez mettre n'importe où (vous pouvez définir votre propre espace réservé, mais je m'en tiens généralement {}car il ne sera pas confondu avec beaucoup d'autres choses.

Mettre tout cela ensemble (en supposant que les commandes que vous avez données font ce que vous pensez qu'elles font!):

find server/lib -type f -exec basename {} \; | cut -f 1 -d '.' | xargs -I {} grep -R --exclude-dir=node_modules {} . -l

Longue réponse

Ok, donc nous pouvons probablement aller plus loin. Disons que vous vouliez le format que vous avez mentionné plus tôt - vous pouvez le xargsfaire sh -cpour pouvoir enchaîner les commandes:

find server/lib -type f -exec basename {} \; | cut -f 1 -d '.' | xargs -I {} sh -c "echo {}; grep -R --exclude-dir=node_modules {} . -l"

En exécutant cela sur ma machine, il semble que cela vous donne les fichiers où le fichier se trouve. Mon cerveau est fatigué, donc au lieu de l'envelopper dans un joli script (ce que vous devriez réellement faire lorsque les oneliners commencent à devenir noueux, et utiliser https://www.shellcheck.net/ pendant que vous y êtes), vous pouvez ayez cet horrible hack à la place, qui (je pense) vous donnera la sortie que vous recherchez:

find server/lib -type f -exec basename {} \; | cut -f 1 -d '.' | xargs -I {} sh -c "echo {}; grep -R --exclude-dir=node_modules {} . -l && printf \"\n\" || printf \"Not found\n\n\""

Pointe
la source
Grand merci, oui xargs -I {}c'est ce que je cherchais.
Simon Legg
6

Avec zsh:

projects=(server/lib/**/*(D.:t:r))
grep -rFl --exclude-dir=node_modules -e${(u)^projects} .
  • **/globbing récursif. Une fonctionnalité introduite par zshau début des années 90.
  • (D.:t:r)est un qualificatif glob, une zshfonctionnalité spécifique qui permet de sélectionner des fichiers en utilisant des attributs autres que le nom, ou de changer le tri ou de faire des modifications sur les fichiers trouvés.
  • D: inclure des fichiers de points et parcourir les répertoires de points comme vous le findferiez. Vous voudrez probablement retirer celui-ci.
  • .: uniquement les fichiers normaux (comme -type fdans find)
  • :t, :r: modificateurs d'historique comme dans csh/ bashmais ici appliqués aux fichiers globés. :tpour la queue (nom de base), :rpour le nom de la racine (extension supprimée).
  • x${^array}distribue les éléments comme rcle ferait « x^$arrayou fish» x$array. Par exemple, si $arrayest ( 1, 2). Cela devient x1 x2.
  • ${(u)array}(pour unique), supprimez les doublons ( (u)étant un indicateur d'extension de paramètre).

Pour la liste des fichiers qui ne contiennent aucune chaîne , remplacez -lpar -L(en supposant GNU grep, mais vous utilisez déjà des options spécifiques à GNU ici). -Fest pour la recherche de chaînes fixes (car vous ne voulez probablement pas que ces noms de projets soient traités comme des expressions rationnelles). Vous pouvez également ajouter une -woption greppour la correspondance de mots afin qu'elle foone corresponde pas foobarpar exemple (correspondrait foo-barquand même).

Stéphane Chazelas
la source
Super merci pour cela et les explications, je n'étais pas au courant de la projects=(server/lib/**/*(D.:t:r))production d'un tableau comme ça dans zsh. Cependant, je dois maintenant répertorier les fichiers où je n'ai greprien trouvé. Je suppose que je devrais attraper un code de sortie 0 / faux?
Simon Legg
@Simon, voir la partie sur -Là la fin de la réponse
Stéphane Chazelas
Oui j'ai vu ça. -lme dit où était le résultat de la recherche et -Lme dit où il n'a pas été trouvé. Mais je veux connaître une liste des termes de recherche qui n'ont été trouvés nulle part plutôt que où ils étaient / n'ont pas été trouvés
Simon Legg