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.
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.
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
}
Basé sur cela DONC, la question :
grep -rIl "needle text" my_folder
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 "" "%"
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|:[^:]*$||'
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 {} \;
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.
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.
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"
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:)
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"
- 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)
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é.
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 debash
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 litnull
séparé,-I @@
prend chaque dossier et utilise comme paramètre de position/args bash script. -
--
pourbash
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"