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.
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
Adapté de fichier binaire exclu
find . -exec file {} \; | grep text | cut -d: -f1
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
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
.
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.
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.
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
Essayez la ligne de commande suivante:
file "$FILE" | grep -vq 'ASCII' && echo "$FILE is binary"
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 |^@^@|
où ^@
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 .
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
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
' _ '{}' +
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 .
Vous pouvez le faire également en utilisant la commande diff
. Vérifiez cette réponse: