Woher weiß ich, ob es sich bei einer Datei um eine Binärdatei handelt?
Zum Beispiel kompilierte c-Datei.
Ich möchte alle Dateien aus einem Verzeichnis lesen, aber ich möchte Binärdateien ignorieren.
Verwenden Sie das Dienstprogramm file
. Verwendungsbeispiel:
$ 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
Angepasst aus ausschließlich Binärdatei
find . -exec file {} \; | grep text | cut -d: -f1
Ich benutze
! grep -qI . $path
Der einzige Nachteil, den ich sehen kann, ist, dass eine leere Datei als Binärdatei betrachtet wird. Aber wer entscheidet, ob dies falsch ist?
Perl -E 'exit((-B $ARGV[0])?0:1);' file-to-test
Kann verwendet werden, um zu überprüfen, wann "file-to-test" binär ist. Der obige Befehl wird mit Code 0 für Binärdateien beendet, andernfalls lautet der Beendigungscode 1.
Die umgekehrte Prüfung für Textdateien kann folgendermaßen aussehen:
Perl -E 'exit((-T $ARGV[0])?0:1);' file-to-test
Ebenso wird der obige Befehl mit Status 0 beendet, wenn die "zu testende Datei" Text ist (nicht binär).
Lesen Sie mehr über die -B
- und -T
-Prüfungen mit dem Befehl perldoc -f -X
.
grep
Hier ist eine einfache Lösung, um nach einer einzelnen Datei mit BSD grep
(unter macOS/Unix) zu suchen:
grep -q "\x00" file && echo Binary || echo Text
im Grunde wird geprüft, ob die Datei NUL-Zeichen enthält.
Wenn Sie mit dieser Methode alle nicht-binären Dateien rekursiv mit dem Dienstprogramm find
lesen, können Sie Folgendes tun:
find . -type f -exec sh -c 'grep -q "\x00" {} || cat {}' ";"
Oder noch einfacher mit grep
:
grep -rv "\x00" .
Verwenden Sie für nur den aktuellen Ordner:
grep -v "\x00" *
Leider funktionieren die obigen Beispiele nicht für GNU grep
, es gibt jedoch eine Problemumgehung.
grep
Da GNU grep
NULL-Zeichen ignoriert, ist es möglich, nach anderen Nicht-ASCII-Zeichen zu suchen wie:
$ grep -P "[^\x00-\x7F]" file && echo Binary || echo Text
Hinweis: Es funktioniert nicht für Dateien, die nur NULL-Zeichen enthalten.
Verwenden Sie den in Perl integrierten -T
Datei-Testoperator, vorzugsweise nachdem Sie festgestellt haben, dass es sich um eine reine Datei handelt, und verwenden Sie den -f
Datei-Operator:
$ 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
Hier ist die Ergänzung dieses Sets:
$ 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
Versuchen Sie die folgende Befehlszeile:
file "$FILE" | grep -vq 'ASCII' && echo "$FILE is binary"
cat
+ grep
Angenommen, binär bedeutet, dass die Datei NULL-Zeichen enthält. Dieser Shell-Befehl kann dabei helfen:
(cat -v file.bin | grep -q "\^@") && echo Binary || echo Text
oder:
grep -q "\^@" <(cat -v file.bin) && echo Binary
Dies ist die Problemumgehung für grep -q "\x00"
, die für BSD grep funktioniert, nicht jedoch für die Version GNU.
Grundsätzlich konvertiert -v
für cat
alle nicht druckbaren Zeichen so, dass sie in Form von Steuerzeichen sichtbar sind. Beispiel:
$ 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 |^@^@|
dabei stehen ^@
-Zeichen für NULL-Zeichen. Sobald diese Steuerzeichen gefunden wurden, gehen wir davon aus, dass die Datei binär ist.
Der Nachteil des obigen Verfahrens besteht darin, dass es falsch positive Ergebnisse erzeugen kann, wenn Zeichen keine Steuerzeichen darstellen. Zum Beispiel:
$ printf "\x00\x00^@^@" | cat -v | hexdump -C
00000000 5e 40 5e 40 5e 40 5e 40 |^@^@^@^@|
Siehe auch: Wie grep ich für alle Nicht-ASCII-Zeichen .
Ausgehen Bachs Vorschlag , ich denke, --mime-encoding
ist die beste Flagge, um etwas zuverlässiges von file
zu erhalten.
file --mime-encoding [FILES ...] | grep -v '\bbinary$'
druckt die Dateien, von denen file
eine nicht-binäre Kodierung erwartet. Sie können diese Ausgabe über cut -d: -f1
weiterleiten, um den : encoding
abzuschneiden, wenn Sie nur die Dateinamen verwenden möchten.
Einschränkung: Da @yugr-Berichte unter .doc
-Dateien eine Kodierung von application/mswordbinary
melden. Das sieht für mich wie ein Fehler aus - der Mime-Typ wird fälschlicherweise mit der Kodierung verkettet.
$ 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
Vielleicht würde das ausreichen ..
if ! file /path/to/file | grep -iq ASCII ; then
echo "Binary"
fi
if file /path/to/file | grep -iq ASCII ; then
echo "Text file"
fi
Es ist eine Art rohe Gewalt, binäre Dateien mit tr -d "[[:print:]\n\t]" < file | wc -c
auszuschließen, aber es ist auch keine heuristische Vermutung.
find . -type f -maxdepth 1 -exec /bin/sh -c '
for file in "[email protected]"; 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
' _ '{}' +
Der folgende Brute-Force-Ansatz mit grep -a -m 1 $'[^[:print:]\t]' file
scheint jedoch etwas schneller zu sein.
find . -type f -maxdepth 1 -exec /bin/sh -c '
tab="$(printf "\t")"
for file in "[email protected]"; 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
Angenommen, binär bedeutet Datei, die nicht druckbare Zeichen enthält (mit Ausnahme von Leerzeichen wie Leerzeichen, Tabulatoren oder neuen Zeilenzeichen). Dies kann funktionieren (sowohl BSD als auch GNU)
$ grep '[^[:print:][:blank:]]' file && echo Binary || echo Text
Hinweis: GNU grep
meldet eine Datei, die nur NULL-Zeichen als Text enthält, funktioniert aber unter BSD-Version ordnungsgemäß.
Weitere Beispiele finden Sie unter: Wie grep ich für alle Nicht-ASCII-Zeichen .
Sie können dies auch tun, indem Sie den Befehl diff
verwenden. Überprüfen Sie diese Antwort: