Как проверить, является ли файл двоичным файлом и читать все файлы, которые нет?

Как узнать, является ли файл двоичным файлом?

Например, скомпилированный файл c.

Я хочу прочитать все файлы из некоторого каталога, но я хочу игнорировать двоичные файлы.

Ответ 1

Использовать утилиту 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

file страница руководства

Ответ 3

Я использую

! grep -qI . $path

Единственный недостаток, который я вижу, заключается в том, что он рассмотрит пустой двоичный файл, но потом снова, кто решит, что это неправильно?

Ответ 4

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.

Ответ 5

Использовать встроенный -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

Ответ 6

BSD 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, однако есть обходной путь.

GNU 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.

Ответ 7

Попробуйте выполнить следующую команду:

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

Ответ 8

Исходя из предложения Баха, я думаю, --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

Ответ 9

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 символов.

Ответ 10

Это своего рода грубая сила, чтобы исключить двоичные файлы с помощью 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
' _ '{}' + 

Ответ 12

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.

Ответ 13

Возможно, этого будет достаточно..

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