Commande Linux: Comment "trouver" seulement des fichiers texte?

après quelques recherches sur Google, ce que J'ai trouvé est:

find my_folder -type f -exec grep -l "needle text" {} ; -exec file {} ; | grep text

qui est très maladroit et produit des textes inutiles tels que des informations de type mime. De meilleures solutions? J'ai beaucoup d'images et d'autres fichiers binaires dans le même dossier avec beaucoup de fichiers texte que j'ai besoin pour effectuer la recherche.

73
demandé sur Shai 2011-01-22 13:55:56

15 réponses

je sais que c'est un vieux fil, mais je suis tombé dessus et j'ai pensé que je partagerais ma méthode que j'ai trouvé être un moyen très rapide d'utiliser find pour trouver seulement des fichiers non-binaires:

find . -type f -exec grep -Iq . {} \; -and -print

l'option -I de grep lui dit d'ignorer immédiatement les fichiers binaires et l'option . ainsi que le -q le fera correspondre immédiatement aux fichiers texte de sorte qu'il va très vite. Vous pouvez remplacer le -print par un -print0 pour la tuyauterie dans un xargs -0 ou quelque chose comme ça si vous vous souciez des espaces (merci pour le tuyau, @lucas.werkmeister!)

aussi le premier point n'est nécessaire que pour certaines versions BSD De find telles que sur OS X, mais cela ne fait pas de mal à quoi que ce soit que de l'avoir là tout le temps si vous voulez le mettre dans un alias ou quelque chose.

132
répondu crudcore 2015-07-22 17:00:50

Pourquoi est-ce mal? Si vous avez besoin de l'utiliser souvent, et que vous ne voulez pas le taper à chaque fois, définissez juste une fonction bash pour elle:

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "" -type f -exec grep -l "" {} \; -exec file {} \; | grep text
}

mettez-le dans votre .bashrc et courez juste:

findTextInAsciiFiles your_folder "needle text"

quand vous voulez.


modifier pour refléter le modifier de L'OP:

si vous voulez découper des informations mime vous pouvez juste ajouter une étape supplémentaire vers le pipeline qui filtre les informations mime. Cela devrait faire l'affaire, en ne prenant que ce qui vient avant : : cut -d':' -f1 :

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "" -type f -exec grep -l "" {} \; -exec file {} \; | grep text | cut -d ':' -f1
}
10
répondu peoro 2011-01-22 11:26:01

Basé sur cela DONC, la question :

grep -rIl "needle text" my_folder

8
répondu crayzeewulf 2017-05-23 12:26:09
find . -type f -print0 | xargs -0 file | grep -P text | cut -d: -f1 | xargs grep -Pil "search"

ce n'est malheureusement pas space save. Mettre ça dans le script de bash rend ça un peu plus facile.

Cet espace est sûre:

#!/bin/bash
#if [ ! "" ] ; then
    echo "Usage: "151910920" <search>";
    exit
fi

find . -type f -print0 \
  | xargs -0 file \
  | grep -P text \
  | cut -d: -f1 \
  | xargs -i% grep -Pil "" "%"
4
répondu anttir 2012-03-17 16:10:36

Que pensez-vous de ceci:

$ grep -rl "needle text" my_folder | tr '\n' '"151900920"' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable'

si vous voulez les noms de fichiers sans les types de fichiers, il vous suffit d'ajouter un filtre final sed .

$ grep -rl "needle text" my_folder | tr '\n' '"151910920"' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'

vous pouvez filtrer les types de fichiers inutiles en ajoutant plus d'options -e 'type' à la dernière commande grep .

EDIT:

si votre version xargs supporte l'option -d , les commandes ci-dessus deviennent plus simples:

$ grep -rl "needle text" my_folder | xargs -d '\n' -r file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'
2
répondu thkala 2011-01-22 11:49:22

voilà comment je l'ai fait ...

1 . faire un petit script pour tester si un fichier texte istext:

#!/bin/bash
[[ "$(file -bi )" == *"file"* ]]

2 . utiliser find comme avant

find . -type f -exec istext {} \; -exec grep -nHi mystring {} \;
2
répondu Robert 2012-03-16 17:45:46

j'ai deux problèmes avec la réponse de l'histoire:

  • liste des fichiers de texte. Il ne les Recherche pas réellement comme demander. Pour effectuer une recherche, utilisez

    find . -type f -exec grep -Iq . {} \; -and -print0 | xargs -0 grep "needle text"
    
  • il génère un processus grep pour chaque fichier, ce qui est très lent. Une meilleure solution est alors

    find . -type f -print0 | xargs -0 grep -IZl . | xargs -0 grep "needle text"
    

    ou simplement

    find . -type f -print0 | xargs -0 grep -I "needle text"
    

    cela prend seulement 0,2 s par rapport à 4s Pour solution ci-dessus (2,5 Go de données / 7700 fichiers), i.e. 20x plus rapide .

aussi, PERSONNE n'a cité ag, le chercheur D'Argent ou ack-grep comme alternatives. Si l'un d'entre eux est disponible, ce sont des alternatives bien meilleures:

ag -t "needle text"    # Much faster than ack
ack -t "needle text"   # or ack-grep

comme dernière note, méfiez-vous des faux positifs (fichiers binaires pris comme des fichiers texte). J'ai déjà eu faux positif en utilisant soit grep / ag / ack, alors mieux vaut lister les fichiers appariés avant d'éditer les fichiers.

2
répondu fuujuhi 2018-01-30 16:05:35

bien qu'il s'agisse d'une question ancienne, je pense que cette info ci-dessous va ajouter à la qualité des réponses ici.

en ignorant les fichiers avec le bit exécutable mis, j'utilise juste cette commande:

find . ! -perm -111

pour l'empêcher d'entrer récursivement dans d'autres répertoires:

find . -maxdepth 1 ! -perm -111

pas besoin de pipes pour mélanger beaucoup de commandes, juste la puissante plaine trouver "1519120920 de la commande".

  • Avertissement: il n'est pas exactement ce que l'OP a demandé, parce qu'il ne vérifie pas si le fichier est binaire ou pas. Il va, par exemple, filtrer bash script fichiers, qui sont texte eux-mêmes, mais ont le bit exécutable réglé .

cela dit, j'espère que cela est utile à personne.

1
répondu Dr Beco 2017-04-15 01:41:14

une Autre façon de faire:

# find . |xargs file {} \; |grep "ASCII text"

si vous voulez des fichiers vides aussi:

#  find . |xargs file {} \; |egrep "ASCII text|empty"
1
répondu The IT Guy 2017-11-03 21:43:33

je le fais de cette façon: 1) comme il y a trop de fichiers (~30k) pour effectuer une recherche, je génère quotidiennement la liste des fichiers textes à utiliser via crontab en utilisant la commande ci-dessous:

find /to/src/folder -type f -exec file {} \; | grep text | cut -d: -f1 > ~/.src_list &

2) Créer une fonction dans .bashrc:

findex() {
    cat ~/.src_list | xargs grep "$*" 2>/dev/null
}

alors je peux utiliser la commande ci-dessous pour faire la recherche:

findex "needle text"

HTH:)

0
répondu Frank Fang 2012-12-26 08:09:27

je préfère xargs

find . -type f | xargs grep -I "needle text"

si vos noms de fichiers sont bizarres, regardez vers le haut en utilisant les options -0:

find . -type f -print0 | xargs -0 grep -I "needle text"
0
répondu dalore 2014-11-04 15:49:37
  • bash exemple pour les moteurs de recherche de texte "eth0" dans /etc dans tous les textes/fichiers ascii

grep eth0 $(find /etc/ -type f-exec file {} \; / egrep-i "text / ascii" / cut-d ':' -f1)

0
répondu Gabriel G 2016-04-01 14:49:50

Voici une version simplifiée avec explication prolongée pour les débutants comme moi qui essaient d'apprendre à mettre plus d'une commande dans une ligne.

si vous deviez écrire le problème par étapes, il ressemblerait à ceci:

// For every file in this directory
// Check the filetype
// If it's an ASCII file, then print out the filename

pour ce faire, nous pouvons utiliser trois commandes UNIX: find , file , et grep .

find vérifiera tous les fichiers du répertoire.

file nous donnera le type de fichier. Dans notre cas, nous sommes à la recherche d'un retour de 'texte ASCII '

grep cherche le mot clé 'ASCII' dans la sortie de file

alors comment pouvons-nous les relier en une seule ligne? Il y a plusieurs façons de le faire, mais je trouve que le faire dans l'ordre de notre pseudo-code a le plus de sens (surtout pour un débutant comme moi).

find ./ -exec file {} ";" | grep 'ASCII'

semble compliqué, mais pas mal quand nous le décomposons:

find ./ = parcourez tous les fichiers de ce répertoire. La commande find imprime le nom de fichier de tout fichier qui correspond à l '"expression", ou ce qui vient après le chemin, qui dans notre cas est le répertoire courant ou ./

la chose la plus importante à comprendre est que tout après ce premier bit va être évalué comme vrai ou faux. Si True, le nom du fichier sera imprimé. Si non, alors la commande se déplace sur.

-exec = ce drapeau est une option dans la commande find qui nous permet d'utiliser le résultat d'une commande autre que l'expression de recherche. C'est comme appeler une fonction à l'intérieur d'une fonction.

file {} = la commande étant appelée à l'intérieur de find . La commande file renvoie une chaîne qui vous dit type d'un fichier. Régulièrement, il ressemblerait à ceci: file mytextfile.txt . Dans notre cas, nous voulons qu'il utilise n'importe quel fichier examiné par la commande find , donc nous mettons dans les accolades {} pour agir comme une variable vide, ou paramètre. En d'autres termes, nous demandons simplement que le système affiche une chaîne de caractères pour chaque fichier du répertoire.

";" = ceci est requis par find et est la marque de ponctuation à la fin de notre -exec commande. Voir le manuel pour 'find' pour plus d'explications si vous en avez besoin en exécutant man find .

| grep 'ASCII' = | c'est une pipe. Pipe prend la sortie de ce qui est à gauche et l'utilise comme entrée à ce qui est à droite. Il prend la sortie de la commande find (une chaîne qui est le type de fichier d'un seul fichier) et la teste pour voir si elle contient la chaîne 'ASCII' . Si c'est le cas, elle renvoie la valeur true.

maintenant, le l'expression à droite de find ./ renvoie true lorsque la commande grep renvoie true. Le tour est joué.

0
répondu mepler 2016-12-06 22:28:44

si vous êtes intéressé à trouver n'importe quel type de fichier par leurs octets magiques en utilisant le impressionnant file utilitaire combiné avec la puissance de find , cela peut venir à portée de main:

$ # Let's make some test files
$ mkdir ASCII-finder
$ cd ASCII-finder
$ dd if=/dev/urandom of=binary.file bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.009023 s, 116 MB/s
$ file binary.file
binary.file: data
$ echo 123 > text.txt
$ # Let the magic begin
$ find -type f -print0 | \
    xargs -0 -I @@ bash -c 'file "$@" | grep ASCII &>/dev/null && echo "file is ASCII: $@"' -- @@

sortie:

file is ASCII: ./text.txt

légende: $ est l'invite d'interpréteur de commandes interactive où nous entrons nos commandes

vous pouvez modifier la partie après && pour appeler un autre script ou faire d'autres choses en ligne aussi bien, i.e. si ce fichier contient la chaîne donnée, cat le fichier entier ou rechercher une chaîne secondaire en elle.

explication:

  • find les éléments qui sont des fichiers
  • Faire xargs alimentation de chaque élément comme une ligne dans une ligne de bash commande / script
  • file vérifie le type de fichier par octet magique, grep vérifie si ASCII existe, si c'est le cas, alors après && votre commande suivante s'exécute.
  • find imprime "résultats de la 1519130920" séparés, c'est bon pour échapper les noms de fichiers avec des espaces et des méta-caractères.
  • xargs , en utilisant -0 option, Les lit null séparé, -I @@ prend chaque dossier et utilise comme paramètre de position/args bash script.
  • -- pour bash assure tout ce qui vient après est un argument, même si elle commence par - comme -c qui pourrait autrement être interprété as bash option

si vous avez besoin de trouver des types autres que ASCII, il suffit de remplacer grep ASCII par un autre type, comme grep "PDF document, version 1.4"

0
répondu sdkks 2018-07-14 15:29:08

Que pensez-vous de ce

 find . -type f|xargs grep "needle text"
-3
répondu Navi 2011-01-22 11:24:25