Je fais un find
puis je reçois une liste de fichiers. Comment puis-je le rediriger vers un autre utilitaire tel que cat
(pour que cat affiche le contenu de tous ces fichiers) et qu’il faille fondamentalement grep
quelque chose à partir de ces fichiers.
Transférer vers un autre processus (bien que cela n'accomplisse pas ce que vous avez dit d'essayer de faire):
command1 | command2
Cela enverra la sortie de commande1 comme entrée de commande2
-exec
sur un find
(cela fera ce que vous voulez faire - mais est spécifique à find
)
find . -name '*.foo' -exec cat {} \;
(Tout ce qui se situe entre find
et -exec
correspond aux prédicats de recherche que vous utilisiez déjà. {}
substituera le fichier particulier que vous avez trouvé dans la commande (cat {}
dans ce cas); \;
doit mettre fin à la commande -exec
.)
envoyer la sortie d'un processus en tant qu'argument de ligne de commande à un autre processus
command2 `command1`
par exemple:
cat `find . -name '*.foo' -print`
(Notez que ce ne sont pas des guillemets normaux (sous le tilde ~ de mon clavier).) Cela enverra la sortie de command1
dans command2
comme arguments de ligne de commande. Notez que les noms de fichiers contenant des espaces (saut de ligne, etc.) seront toutefois divisés en arguments séparés.
POSIX 2008 a ajouté le marqueur +
à find
, ce qui signifie qu'il regroupe désormais automatiquement autant de fichiers que nécessaire dans une seule commande, à l'instar de xargs
, mais avec un certain nombre d'avantages:
Le problème de nom de fichier est un problème avec xargs
sans l'option -0
, et le problème "exécuter même sans nom de fichier" est un problème avec ou sans l'option -0
- mais GNU xargs
a l'option -r
ou --no-run-if-empty
pour empêcher cela. En outre, cette notation réduit le nombre de processus, même si vous ne mesurerez probablement pas la différence de performance. Par conséquent, vous pourriez raisonnablement écrire:
find . -exec grep something {} +
find . -print | xargs grep something
Si vous êtes sous Linux ou que vous avez les commandes GNU find
et xargs
, utilisez -print0
avec find
et -0
avec xargs
pour gérer les noms de fichiers contenant des espaces et d'autres caractères de boule impaire. .
find . -print0 | xargs -0 grep something
grep
Si vous ne voulez pas que les noms de fichier (uniquement le texte), ajoutez une option appropriée à grep
(généralement -h
pour supprimer les en-têtes). Pour garantir absolument que le nom de fichier est imprimé par grep
(même si un seul fichier est trouvé ou si le dernier appel de grep
n’est donné qu’un seul nom de fichier), ajoutez ensuite /dev/null
à la ligne de commande xargs
, de sorte toujours être au moins deux noms de fichier.
Il existe plusieurs manières de passer la liste des fichiers renvoyés par la commande find
à la commande cat
, bien que techniquement, ils n'utilisent pas tous la tuyauterie, et aucun ne dirige directement directement vers cat
.
Le plus simple consiste à utiliser des backticks (`
):
cat `find [whatever]`
Cela prend la sortie de find
et la place effectivement sur la ligne de commande de cat
. Cela ne fonctionne pas bien si find
a trop de sorties (plus que ne peut en contenir une ligne de commande) ou si la sortie contient des caractères spéciaux (comme des espaces).
Dans certains shells, y compris bash
, on peut utiliser $()
au lieu de backticks:
cat $(find [whatever])
Ceci est moins portable, mais est emboîtable. En dehors de cela, il a à peu près les mêmes mises en garde que les backticks.
Comme exécuter d'autres commandes sur ce qui a été trouvé est une utilisation courante de find
, find possède une action -exec
qui exécute une commande pour chaque fichier trouvé:
find [whatever] -exec cat {} \;
Le {}
est un espace réservé pour le nom de fichier et le \;
marque la fin de la commande (il est possible d’avoir d’autres actions après -exec
.)
Ceci exécutera cat
une fois pour chaque fichier plutôt que d'exécuter une seule instance de cat
en lui donnant plusieurs noms de fichiers qui peuvent être inefficaces et peuvent ne pas avoir le comportement souhaité pour certaines commandes (bien que cela soit correct pour cat
). La syntaxe est également délicate à saisir - vous devez échapper au point-virgule, car celui-ci est spécial pour le shell!
Certaines versions de find
(notamment la version GNU) vous permettent de remplacer ;
par +
d'utiliser le mode d'ajout de -exec
pour exécuter moins d'instances de cat
:
find [whatever] -exec cat {} +
Cela passera par plusieurs noms de fichiers à chaque appel de cat
, ce qui peut être plus efficace.
Notez que ceci est pas garanti d'utiliser un seul appel, cependant. Si la ligne de commande est trop longue, les arguments sont répartis sur plusieurs invocations de cat
. Pour cat
ce n'est probablement pas un problème, mais pour d'autres commandes, cela peut modifier le comportement de manière indésirable. Sur les systèmes Linux, la limite de longueur de ligne de commande est assez grande. Par conséquent, le fractionnement en plusieurs appels est assez rare par rapport à certains autres systèmes d'exploitation.
L’approche classique/portable consiste à utiliser xargs
:
find [whatever] | xargs cat
xargs
exécute la commande spécifiée (cat
, dans ce cas) et ajoute des arguments en fonction de ce qu'elle lit à partir de stdin. Tout comme -exec
avec +
, cela rompra la ligne de commande si nécessaire. Autrement dit, si find
génère trop de sorties, il exécutera cat
plusieurs fois. Comme mentionné dans la section précédente sur -exec
, il existe certaines commandes dans lesquelles cette division peut entraîner un comportement différent. Notez que l'utilisation de xargs
de cette façon pose des problèmes d'espaces dans les noms de fichiers, car xargs
n'utilise que les espaces blancs comme délimiteur.
La méthode la plus robuste, la plus portable et la plus efficace utilise également xargs
:
find [whatever] -print0 | xargs -0 cat
Le drapeau -print0
indique à find
d'utiliser les délimiteurs \0
(caractère nul) entre les noms de fichiers, et le drapeau -0
indique à xargs
d'attendre que ces \0
les délimiteurs. Cela a un comportement à peu près identique à l’approche -exec
...+
, bien qu’il soit plus portable (mais malheureusement plus détaillé).
Pour ce faire (en utilisant bash) je ferais comme suit:
cat $(find . -name '*.foo')
Ceci est connu comme la "substitution de commande" et il supprime le saut de ligne par défaut, ce qui est très pratique!
plus d'infos ici
Cela ressemble à un travail pour un script Shell pour moi:
for file in 'find -name *.xml'
do
grep 'hello' file
done
ou quelque chose comme ça
Voici mon moyen de trouver des noms de fichiers contenant du contenu qui m'intéresse, juste une seule ligne bash qui gère également les espaces dans les noms de fichiers:
find . -name \*.xml | while read i; do grep '<?xml' "$i" >/dev/null; [ $? == 0 ] && echo $i; done
J'utilise quelque chose comme ça:
find . -name <filename> -print0 | xargs -0 cat | grep <Word2search4>
Les arguments "-print0
" pour "find" et "-0
" pour "xargs" sont nécessaires pour gérer correctement les espaces dans les chemins/noms de fichiers.
La commande find a un argument -exec que vous pouvez utiliser pour des choses comme celle-ci, vous pouvez simplement faire le grep directement en utilisant cela.
Par exemple ( à partir d'ici, d'autres bons exemples sur cette page ):
find . -exec grep "www.athabasca" '{}' \; -print
Dans Bash, ce qui suit serait approprié:
find /dir -type f -print0 | xargs -0i cat {} | grep whatever
Ceci trouvera tous les fichiers dans le répertoire /dir
et les acheminera en toute sécurité vers xargs
, ce qui conduira en toute sécurité grep
.
Sauter xargs
n’est pas une bonne idée si vous avez plusieurs milliers de fichiers dans /dir
; cat
s'arrêtera en raison d'une longueur excessive de la liste d'arguments. xargs
va tout régler pour vous.
L'argument -print0
de find
est associé à l'argument -0
de xargs
pour gérer correctement les noms de fichiers avec des espaces. L'argument -i
de xargs
vous permet d'insérer le nom de fichier si nécessaire dans la ligne de commande cat
. Les crochets sont remplacés par le nom du fichier inséré dans la commande cat
à partir de find
.
Voici mon coup pour un usage général:
grep YOURSTRING `find .`
Il va imprimer le nom du fichier
Ça marche pour moi
find _CACHE_* | while read line; do
cat "$line" | grep "something"
done
Ceci imprimera le nom et le contenu des fichiers uniquement de manière récursive.
find . -type f -printf '\n\n%p:\n' -exec cat {} \;
Utilisez ggrep .
ggrep -H -R -I "mysearchstring" *
rechercher un fichier sous Unix contenant du texte situé dans le répertoire en cours ou dans un sous-répertoire