Как узнать, является ли файл двоичным файлом?
Например, скомпилированный файл c.
Я хочу прочитать все файлы из некоторого каталога, но я хочу игнорировать двоичные файлы.
Как узнать, является ли файл двоичным файлом?
Например, скомпилированный файл c.
Я хочу прочитать все файлы из некоторого каталога, но я хочу игнорировать двоичные файлы.
Использовать утилиту file
, использование примера:
$ 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
Адаптировано из исключая двоичный файл
find . -exec file {} \; | grep text | cut -d: -f1
Я использую
! grep -qI . $path
Единственный недостаток, который я вижу, заключается в том, что он рассмотрит пустой двоичный файл, но потом снова, кто решит, что это неправильно?
perl -E 'exit((-B $ARGV[0])?0:1);' file-to-test
Может использоваться для проверки всякий раз, когда "файл-к-тесту" является двоичным. Вышеупомянутая команда выйдет из wit-кода 0 в двоичных файлах, иначе код выхода будет равен 1.
Обратная проверка текстового файла может выглядеть следующим образом:
perl -E 'exit((-T $ARGV[0])?0:1);' file-to-test
Аналогично вышеприведенная команда выйдет со статусом 0, если "файл для теста" является текстовым (не бинарным).
Подробнее о проверках -B
и -T
, используя команду perldoc -f -X
.
Использовать встроенный -T
файл проверки файлов Perls, желательно после выяснения того, что это простой файл с помощью оператора тестирования файла -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
Вот дополнение этого множества:
$ 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
grep
Вот простое решение для проверки одного файла с помощью BSD grep
(в macOS/Unix):
grep -q "\x00" file && echo Binary || echo Text
который в основном проверяет, содержит ли файл символ NUL.
Используя этот метод, рекурсивно читать все недвоичные файлы с помощью утилиты find
:
find . -type f -exec sh -c 'grep -q "\x00" {} || cat {}' ";"
Или даже проще, используя только grep
:
grep -rv "\x00" .
Для текущей папки используйте:
grep -v "\x00" *
К сожалению, приведенные выше примеры не будут работать для GNU grep
, однако есть обходной путь.
grep
Поскольку GNU grep
игнорирует NULL-символы, можно проверить наличие других не ASCII-символов, например:
$ grep -P "[^\x00-\x7F]" file && echo Binary || echo Text
Note: It won't work for files containing only NULL characters.
Попробуйте выполнить следующую команду:
file "$FILE" | grep -vq 'ASCII' && echo "$FILE is binary"
Исходя из предложения Баха, я думаю, --mime-encoding
- лучший флаг, чтобы получить что-то надежное от file
.
file --mime-encoding [FILES ...] | grep -v '\bbinary$'
напечатает файлы, которые, как считает file
, имеют недвоичное кодирование. Вы можете передать этот вывод через cut -d: -f1
, чтобы обрезать : encoding
, если вам нужны только имена файлов.
Предостережение: как @yugr сообщает ниже .doc
, файлы сообщают кодировку application/mswordbinary
. Это выглядит для меня как ошибка - тип mime ошибочно объединяется с кодировкой.
$ 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
cat
+ grep
Предполагая, что двоичный означает файл, содержащий символы NULL, эта команда оболочки может помочь:
(cat -v file.bin | grep -q "\^@") && echo Binary || echo Text
или:
grep -q "\^@" <(cat -v file.bin) && echo Binary
Это обходной путь для grep -q "\x00"
, который работает для grep BSD, но не для версии GNU.
В основном -v
для cat
преобразует все непечатаемые символы, чтобы они были видны в виде управляющих символов, например:
$ 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 |^@^@|
где символы ^@
обозначают символ NULL. Поэтому, как только эти управляющие символы найдены, мы предполагаем, что файл является двоичным.
Недостаток описанного выше метода заключается в том, что он может генерировать ложные срабатывания, когда символы не представляют управляющие символы. Например:
$ printf "\x00\x00^@^@" | cat -v | hexdump -C
00000000 5e 40 5e 40 5e 40 5e 40 |^@^@^@^@|
См. также: Как выполнить grep для всех не-ASCII символов.
Это своего рода грубая сила, чтобы исключить двоичные файлы с помощью tr -d "[[:print:]\n\t]" < file | wc -c
, но это не эвристическое догадки.
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
' _ '{}' +
Следующий подход грубой силы с использованием grep -a -m 1 $'[^[:print:]\t]' file
кажется довольно быстрым.
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
' _ '{}' +
Вы также можете использовать команду diff
. Проверьте этот ответ:
grep
Предполагая, что двоичный файл означает файл, содержащий непечатаемые символы (исключая пустые символы, такие как пробелы, символы табуляции или символы новой строки), это может работать (как для BSD, так и для GNU):
$ grep '[^[:print:][:blank:]]' file && echo Binary || echo Text
Note: GNU [TG42] will report file containing only NULL characters as text, but it would work correctly on BSD version.
For more examples, see: How do I grep for all non-ASCII characters.
Возможно, этого будет достаточно..
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