Les utilitaires Unix standard aiment grep
et diff
utilisent une heuristique pour classer les fichiers en "texte" ou "binaire". ( grep
La sortie de Eg peut inclure des lignes telles que Binary file frobozz matches
.)
Existe-t-il un test pratique que l'on peut appliquer dans un zsh
script pour effectuer une classification similaire "texte / binaire"? (Autre que quelque chose comme grep '' somefile | grep -q Binary
.)
(Je réalise qu'un tel test serait nécessairement heuristique et donc imparfait.)
file
est un utilitaire standard et peut utiliser la magie de fichier pour déterminer au mieux ses types de fichier. Il peut dire la plupart des formats de texte et fait un travail assez décent sur les formats binaires. Si tout ce que vous essayez, c'est de savoir si un fichierfile
seront imprimées, par exempleshell script
, pour certains fichiers, je voudrais classer le fichier comme "texte". Existe-t-il un moyenfile
d’imprimer simplementtext
oubinary
?cut
commandes.file
sortie de tuyauteriecut
est la solution - bien sûr, il manque un espace qui le fait échouer et qui a rendu la plupart des gens s’adressent au Y au lieu du X mais les commentaires et la réponse de Stéphane montrent la bonne façon de déterminer si le fichier est textuel ou non.Réponses:
Si vous demandez
file
uniquement le type mime, vous obtiendrez de nombreux types commetext/x-shellscript
,application/x-executable
etc., mais j'imagine que si vous vérifiez simplement la partie "texte", vous devriez obtenir de bons résultats. Par exemple (-b
pour aucun nom de fichier dans la sortie):la source
file
, que vous risquez de manquer certains formats de texte:application/xml
(et similaire comme RSS),application/ecmascript
,application/json
,image/svg+xml
, ... Vous auriez à whitelist ceux -ci .application/*
types ne sont pas destinés à la consommation humaine, même s'ils peuvent être basés sur du texte pour faciliter le développement et le débogage. C'est pourquoi il y a à la fois untext/xml
et unapplication/xml
. La question de savoir si les considérer comme un texte dépend des besoins du PO.cut -d/ -f1
Une autre approche consisterait à utiliser
isutf8
la collection moreutils .Il se ferme avec 0 si le fichier est valide UTF-8 ou ASCII, ou court-circuite, imprime un message d'erreur (silence avec
-q
) et se ferme avec 1 sinon.la source
Si vous aimez l'heuristique utilisée par GNU
grep
, vous pouvez l'utiliser:Il recherche les octets NUL dans le premier tampon lu dans le fichier (quelques kilo-octets pour un fichier normal, mais peut être beaucoup moins pour un tuyau, un socket ou des périphériques similaires
/dev/random
). Dans les paramètres régionaux UTF-8, il marque également les séquences d'octets qui ne forment pas des caractères UTF-8 valides. Cela suppose queLC_ALL
la langue n’est pas l’anglais.Le
${1-$REPLY}
formulaire vous permet de l'utiliser commezsh
qualificatif global:dresserait une liste des binaires fichiers.
la source
Vous pouvez essayer de déterminer si vous
iconv
pouvez lire le fichier. Ceci est moins performant quefile
(qui ne lit que quelques octets dès le début), mais vous donnera des résultats plus fiables:Cela rend
iconv
fondamentalement un no-op, mais si il rencontre des données non valides (UTF-8 non valide dans cet exemple), il fera un brouillage et se fermera.la source
-f
et-t
au lieu des options longues GNU le rendrait plus portable. Notez qu'il appellera "binaire" les fichiers qu'il ne peut pas ouvrir. Il appellera les fichiers vides "texte".iconv
. Mais-f
et-t
sont généralement mieux.Vous pouvez écrire un script qui appelle
file
et utiliser une instruction case pour vérifier les cas qui vous intéressent.Par exemple
bien sûr, il peut y avoir de nombreux cas particuliers qui présentent un intérêt. En vérifiant
strings
une copie delibmagic
, je vois environ 200 cas, par exemple,Certains utilisent la chaîne "text" dans le cadre d’un type différent, par exemple,
de même
script
pourrait faire partie d'un mot, mais je ne vois pas de problèmes dans ce cas. Mais un script doit rechercher"text"
un mot , pas une sous - chaîne .Pour rappel, la
file
sortie n'utilise pas de description précise qui aurait toujours un "script" ou un "texte". Les cas spéciaux sont quelque chose à considérer. Un suivi a commenté que les--mime-type
travaux fonctionnent alors que cette approche ne fonctionnerait pas, pour les.svg
fichiers. Cependant, dans un test, je vois ces résultats pour les fichiers svg:que j’ai sélectionné après avoir vu un millier de fichiers ne montrer que 6 avec "texte" dans la sortie de type mime. Faire correspondre le "xml" à la fin de la sortie de type mime pourrait être plus utile, par exemple, que faire correspondre le "SVG", mais utiliser un script pour le faire vous ramène à la suggestion faite ici.
La sortie de
file
nécessite un peu d'ajustage dans les deux cas de figure et n'est pas fiable à 100% (plusieurs de mes scripts Perl le confondent et l'appellent "données").Il y a plus d'une implémentation de
file
. Celui qui est le plus couramment utilisé fait son travaillibmagic
, qui peut être utilisé à partir de différents programmes (peut-être pas directement à partir dezsh
, bien quepython
possible).Selon le tableau de comparaison des tests de fichiers pour shell, Perl, Ruby et Python , Perl dispose d’une
-T
option qu’il peut utiliser pour fournir ces informations. Mais il ne contient aucune caractéristique comparable pourzsh
.Lectures complémentaires:
la source
file
la sortie de GNU pour les fichiers svg:SVG Scalable Vector Graphics image
ne contient pas le mot text. Je pensais que cette approche serait meilleure que la réponse acceptée consistant à vérifier le type mime, mais il manque encore certains types.image/svg+xml
. En fait - je viens de cocher un fichier de 1000 fichiers, seulement 6 sont sortis sous forme de "texte" en fonction du type mime seul. Je vais m'en tenir à un script, qui au moins peut être fait fonctionner au besoin.file
a une option--mime-encoding
qui tente de détecter l'encodage d'un fichier.Vous pouvez utiliser
file --mime-encoding | grep binary
pour détecter si un fichier est un fichier binaire. Cela fonctionne de manière fiable, même si un seul caractère non valide dans un long fichier texte peut compliquer les choses.Par exemple, j'appelle
cat
le script suivant pour éviter de ruiner mon terminal en ouvrant par inadvertance un fichier binaire:la source
Les catégories sont arbitraires. Avant de répondre à la question de savoir comment faire une classification, vous avez besoin d’une définition (stricte). Pour avoir une définition, vous avez besoin d'un objectif .
Alors, que voulez-vous faire avec cette classification?
la source
le fera. Voir la documentation pour
-B
et-T
(recherchez dans cette page la chaîneThe -T and -B switches work as follows
).la source
perl -le 'print -B $ARGV[0] ? "binary" : "text"' --
pourrait être plus clair. Ou mêmeperl -le 'print -B $_ ? "binary" : "text", @ARGV > 1 ? "\t$_" : "" for @ARGV' --
J'ai contribué à https://github.com/audreyr/binaryornot Il n'a pas (encore) d'encapsuleur de ligne de commande, mais c'est une simple bibliothèque Python assez facile à appeler même à partir de la CLI. Il utilise une heuristique assez efficace pour déterminer si un fichier est du texte ou du binaire.
la source
Maintenant, cette réponse est un peu ancienne, mais je pense que mon ami m'a appris un grand "hack" à faire cela.
Vous utilisez la
diff
commande et vérifiez votre fichier par rapport à un fichier texte de test:$ diff filetocheck testfile.txt
Maintenant si
filetocheck
est un fichier binaire, le résultat serait:Binary files filetocheck and testfile.txt differ
De cette façon, vous pouvez exploiter la
diff
commande et écrire par exemple une fonction qui effectue la vérification dans un script.la source