web-dev-qa-db-fra.com

Comment redistribuer la liste des fichiers renvoyés par la commande find à cat pour afficher tous les fichiers

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.

189
Devang Kamdar
  1. 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

  2. -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.)

  3. 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.

306
kenj0418

Version moderne

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:

  1. Vous n'avez pas à vous soucier des caractères impairs dans les noms de fichiers.
  2. Vous n'avez pas à vous soucier de l'invocation de la commande avec zéro nom de fichier.

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 {} +

Version classique

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

Modification des résultats de 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.

80
Jonathan Leffler

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.

  1. 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).

  2. 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.

  3. 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!

  4. 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.

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

  6. 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é).

34

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

9
Stphane

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

6
Gandalf

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
4
Greg

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.

3
ekinak

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 
2
Chad Birch

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.

2
McClain Looney

Voici mon coup pour un usage général:

grep YOURSTRING `find .`

Il va imprimer le nom du fichier

2
zakki

Ça marche pour moi

find _CACHE_* | while read line; do
    cat "$line" | grep "something"
done
0
Steven Penny

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 {} \;
0
Prashant Adlinge

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

0
Underverse