web-dev-qa-db-fra.com

Comment vérifier si le fichier est un fichier binaire et lire tous les fichiers qui ne le sont pas?

Comment savoir si un fichier est un fichier binaire?

Par exemple, fichier c compilé.

Je veux lire tous les fichiers de certains répertoires, mais je veux ignorer les fichiers binaires.

38
Refael

Utilisez l'utilitaire file, exemple d'utilisation:

 $ file /bin/bash
 /bin/bash: Mach-O universal binary with 2 architectures
 /bin/bash (for architecture x86_64):   Mach-O 64-bit executable x86_64
 /bin/bash (for architecture i386): Mach-O executable i386

 $ file /etc/passwd
 /etc/passwd: ASCII English text

 $ file code.c
 code.c: ASCII c program text

file page de manuel

43
Adam Siemion

Adapté de fichier binaire exclu

find . -exec file {} \; | grep text | cut -d: -f1
9
gongzhitaao

J'utilise

! grep -qI . $path

Le seul inconvénient que je peux voir est qu’il considérera un fichier binaire vide, mais encore une fois, qui décide s’il est faux

8
Alois Mahdal
Perl -E 'exit((-B $ARGV[0])?0:1);' file-to-test

Peut être utilisé pour vérifier si "fichier à tester" est binaire. La commande ci-dessus va quitter le code 0 sur les fichiers binaires, sinon le code de sortie serait 1.

La vérification inverse du fichier texte peut ressembler à la commande suivante:

Perl -E 'exit((-T $ARGV[0])?0:1);' file-to-test

De même, la commande ci-dessus quittera avec l'état 0 si le "fichier à tester" est du texte (et non du binaire).

En savoir plus sur les contrôles -B et -T à l'aide de la commande perldoc -f -X.

4
Onlyjob

BSD grep

Voici une solution simple pour rechercher un fichier unique à l’aide de BSD grep (sous macOS/Unix):

grep -q "\x00" file && echo Binary || echo Text

qui vérifie fondamentalement si le fichier est composé du caractère NUL.

En utilisant cette méthode, pour lire tous les fichiers non-binaires de manière récursive à l'aide de l'utilitaire find, vous pouvez effectuer les opérations suivantes:

find . -type f -exec sh -c 'grep -q "\x00" {} || cat {}' ";"

Ou encore plus simple en utilisant simplement grep:

grep -rv "\x00" .

Pour seulement le dossier actuel, utilisez:

grep -v "\x00" *

Malheureusement, les exemples ci-dessus ne fonctionneront pas pour GNU grep , mais il existe une solution de contournement.

GNU grep

Puisque GNU grep ignore les caractères NULL, il est possible de rechercher d’autres caractères non-ASCII like:

$ grep -P "[^\x00-\x7F]" file && echo Binary || echo Text

Remarque: cela ne fonctionnera pas pour les fichiers contenant uniquement des caractères NULL.

3
kenorb

Utilisez l'opérateur de test de fichier -T intégré de Perl, de préférence après vous être assuré qu'il s'agit d'un fichier ordinaire utilisant l'opérateur de test de fichier -f:

$ Perl -le 'for (@ARGV) { print if -f && -T }' \
    getwinsz.c a.out /etc/termcap /bin /bin/cat \
    /dev/tty /usr/share/zoneinfo/UTC /etc/motd
getwinsz.c
/etc/termcap
/etc/motd

Voici le complément de cet ensemble:

$ Perl -le 'for (@ARGV) { print unless -f && -T }' \
    getwinsz.c a.out /etc/termcap /bin /bin/cat \
    /dev/tty /usr/share/zoneinfo/UTC /etc/motd
a.out
/bin
/bin/cat
/dev/tty
/usr/share/zoneinfo/UTC
2
tchrist

Essayez la ligne de commande suivante:

file "$FILE" | grep -vq 'ASCII' && echo "$FILE is binary"
1
user1985553

cat + grep

En supposant que binaire signifie que le fichier contient des caractères NULL, cette commande Shell peut vous aider:

(cat -v file.bin | grep -q "\^@") && echo Binary || echo Text

ou:

grep -q "\^@" <(cat -v file.bin) && echo Binary

C'est la solution de contournement pour grep -q "\x00" , qui fonctionne pour BSD grep, mais pas pour la version GNU.

En gros, -v pour cat convertit tous les caractères non imprimables afin qu'ils soient visibles sous forme de caractères de contrôle, par exemple:

$ printf "\x00\x00" | hexdump -C
00000000  00 00                                             |..|
$ printf "\x00\x00" | cat -v
^@^@
$ printf "\x00\x00" | cat -v | hexdump -C
00000000  5e 40 5e 40                                       |^@^@|

^@ caractères représentent le caractère NULL. Donc, une fois que ces caractères de contrôle sont trouvés, nous supposons que le fichier est binaire.


L'inconvénient de la méthode ci-dessus est qu'il peut générer des faux positifs lorsque les caractères ne représentent pas des caractères de contrôle. Par exemple:

$ printf "\x00\x00^@^@" | cat -v | hexdump -C
00000000  5e 40 5e 40 5e 40 5e 40                           |^@^@^@^@|

Voir aussi: Comment puis-je grep pour tous les caractères non-ASCII .

1
kenorb

Quitter La suggestion de Bach , Je pense que --mime-encoding est le meilleur drapeau pour obtenir quelque chose de fiable de file .

file --mime-encoding [FILES ...] | grep -v '\bbinary$'

imprimera les fichiers dont file estime qu’ils ont un codage non binaire. Vous pouvez diriger cette sortie via cut -d: -f1 pour couper le : encoding si vous souhaitez simplement les noms de fichiers.


Avertissement: selon les rapports @yugr ci-dessous, les fichiers .doc indiquent un codage de application/mswordbinary. Cela me ressemble à un bug - le type mime est concaténé par erreur avec l'encodage.

$ for flag in --mime --mime-type --mime-encoding; do
    echo "$flag"
    file "$flag" /tmp/example.{doc{,x},png,txt}
  done
--mime
/tmp/example.doc:  application/msword; charset=binary
/tmp/example.docx: application/vnd.openxmlformats-officedocument.wordprocessingml.document; charset=binary
/tmp/example.png:  image/png; charset=binary
/tmp/example.txt:  text/plain; charset=us-ascii
--mime-type
/tmp/example.doc:  application/msword
/tmp/example.docx: application/vnd.openxmlformats-officedocument.wordprocessingml.document
/tmp/example.png:  image/png
/tmp/example.txt:  text/plain
--mime-encoding
/tmp/example.doc:  application/mswordbinary
/tmp/example.docx: binary
/tmp/example.png:  binary
/tmp/example.txt:  us-ascii
1
dimo414

C'est une sorte de force brutale d'exclure des fichiers binaires avec tr -d "[[:print:]\n\t]" < file | wc -c, mais ce n'est pas une hypothèse heuristique non plus.

find . -type f -maxdepth 1 -exec /bin/sh -c '
   for file in "$@"; do
      if [ $(LC_ALL=C LANG=C tr -d "[[:print:]\n\t]" < "$file" | wc -c) -gt 0 ]; then
         echo "${file} is no ASCII text file (UNIX)"
      else
         echo "${file} is ASCII text file (UNIX)"
      fi
   done
' _ '{}' +

L’approche brute-force suivante utilisant grep -a -m 1 $'[^[:print:]\t]' file semble cependant un peu plus rapide.

find . -type f -maxdepth 1 -exec /bin/sh -c '
   tab="$(printf "\t")"
   for file in "$@"; do
      if LC_ALL=C LANG=C grep -a -m 1 "[^[:print:]${tab}]" "$file" 1>/dev/null 2>&1; then
         echo "${file} is no ASCII text file (UNIX)"
      else
         echo "${file} is ASCII text file (UNIX)"
      fi
   done
' _ '{}' + 
0
vron

grep

En supposant que binaire signifie qu'un fichier contenant des caractères non imprimables (à l'exclusion des caractères vierges tels que des espaces, des tabulations ou des caractères de nouvelle ligne), cela peut fonctionner (BSD et GNU):

$ grep '[^[:print:][:blank:]]' file && echo Binary || echo Text

Remarque: GNU grep rapportera le fichier contenant uniquement des caractères NULL sous forme de texte, mais cela fonctionnera correctement sur version BSD .

Pour plus d'exemples, voir: Comment puis-je grep pour tous les caractères non-ASCII .

0
kenorb

Vous pouvez le faire également en utilisant la commande diff. Vérifiez cette réponse:

https://unix.stackexchange.com/questions/275516/is-there-a-convenient-way-to-classify-files-as-binary-or-text#answer-402870

0
tonix