Je voulais une command en command line pour searchr tous les scripts shell dans le système de files pour un mot particulier, alors j'ai demandé autour de travail et a obtenu les solutions suivantes:
grep word `find / -name \*.sh 2>/dev/null` find / -name "*.sh" 2>/dev/null | xargs grep word
Cependant, je ne suis pas familier avec la command line, donc ces deux solutions me semblent opaques. Je préférerais faire quelque chose qui ressemble à ceci:
ls -r *.sh | cat | grep -H word
Mais il semble que vous ne pouvez pas canaliser les noms de files dans le chat (au less, je pense que c'est ce que le problème est).
Quelle est la solution la plus lisible? Et deuxièmement, quelle est la solution la plus efficace?
Edit: J'ai besoin de savoir dans quel file le mot a été trouvé, afin de pouvoir modifier le script.
Edit: Si vous avez des utilitaires GNU, voir la réponse de Gilles pour une méthode utilisant les capacités de recursion de GNU grep
qui est beaucoup plus simple que l'approche find
. Si vous voulez seulement afficher les noms de files, vous voudrez toujours append l'option -l
comme décrit ci-dessous.
Utilisez grep -l word
pour imprimer uniquement les noms des files contenant une correspondance.
Si vous voulez find tous les files du système de files se terminant par .sh
, à partir de la racine /
, find
est l'outil le plus approprié.
La recommandation la plus portable et la plus efficace est la suivante:
find / -type f -name '*.sh' -exec grep -l word {} + 2>/dev/null
C'est à peu près aussi lisible que possible et n'est pas difficile à parsingr si vous comprenez la sémantique derrière chacun des composants.
find /
: run find
partir de la racine du système de files, /
-type f
: ne correspond qu'aux files réguliers -name '*.sh'
: … et ne correspondent qu'aux files dont les noms se terminent par .sh
-exec ... {} +
: exécutez la command spécifiée dans ...
sur les files correspondants dans les groupes, où {}
est remplacé par les noms de file dans le groupe. L'idée est d'exécuter la command sur autant de files à la fois que possible dans les limites du système ( ARG_MAX
). L'efficacité de la forme {} +
provient de la minimisation du nombre de fois que la command ...
doit être appelée en maximisant le nombre de files transmis à chaque invocation de ...
grep -l word {}
: où le {}
est le même {}
répété d'en haut et est remplacé par des noms de file. Comme expliqué précédemment, grep -l
imprime les noms des files contenant une correspondance pour le word
. 2>/dev/null
: cacher les messages d'erreur (techniquement, redirect l'erreur standard vers le trou noir qui est /dev/null
). C'est pour des raisons esthétiques et pratiques, car la find
cours sur /
entraînera vraisemblablement des rames de messages "permission denied" qui ne vous intéressent pas pour les files que vous n'avez pas la permission de lire et les directorys que vous n'avez pas la permission de parcourir. Il y a quelques problèmes avec les suggestions que vous avez reçues et affichées dans votre question. Tous les deux
grep word `find / -name \*.sh 2>/dev/null
et
find / -name "*.sh" 2>/dev/null | xargs grep word
échouer sur les files avec des espaces dans leur nom. Il est préférable d'éviter de placer les noms de files dans la substitution de command. Le premier a le problème supplémentaire de potentiellement courir dans la limite ARG_MAX. Le second est proche de ce que je suggère, mais il n'y a pas de bonne raison d'utiliser xargs
ici, sans mentionner que l'utilisation sûre et correcte de xargs
nécessite de sacrifier la portabilité pour certaines options GNU-only ( find -print0 | xargs -0
).
Sur Linux non embarqué, Cygwin ou autre système avec GNU grep , sous FreeBSD , sous NetBSD et OSX :
grep -r --include='*.sh' word .
Ne pas parsingr la sortie de ls
. Et n'utilisez pas de substitution de command sur la sortie de find
, comme l' a expliqué jw013 .
La combinaison de grep
et find
est dans de nombreux cas ack
( betterthangrep.com ):
ack [OPTION]... PATTERN [FILE]
Pour votre exemple, envisagez d'utiliser
ack --shell word /
ack
.git
, .hg
, .svn
, … grep
et les mêmes arguments / similaires comme -i
pour "ignorer la casse" etc. ack-grep
sur votre système (sur les dissortingbutions basées sur Debian, si je me souviens bien) L'option --shell
est courte pour --type=shell
et inclut plusieurs types de files: actuellement .sh .bash .csh .tcsh .ksh .zsh
selon
ack --help-types
Si vous ne voulez que des files .sh
, vous devez définir (append) votre propre type sh
et utiliser ce filter ( --sh
) comme ceci:
ack word --type-add=sh=.sh --sh /
Cela semble un peu compliqué, mais permet la search récursive pour les files .sh
ci /
dessous /
. Pour une search locale (sans spécifier le directory de départ, par exemple \
), ce serait plus simple:
ack word *.sh