¿Cómo comprobar si el archivo es un archivo binario y leer todos los archivos que no lo son?


¿Cómo puedo saber si un archivo es un archivo binario?

Por ejemplo, archivo c compilado.

Quiero leer todos los archivos de algún directorio, pero quiero ignorar archivos binarios.

Author: kenorb, 2013-05-26

12 answers

Use la utilidad file, ejemplo de uso:

 $ 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 página de manual

 40
Author: Adam Siemion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-26 14:57:02

Adaptado de excluyendo el archivo binario

find . -exec file {} \; | grep text | cut -d: -f1
 9
Author: gongzhitaao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-26 15:47:00

Utilizo

! grep -qI . $path

El único inconveniente que puedo ver es que considerará un archivo binario vacío pero, de nuevo, ¿quién decide si eso está mal?

 8
Author: Alois Mahdal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-10 01:54:08
perl -E 'exit((-B $ARGV[0])?0:1);' file-to-test

Se podría usar para verificar siempre que "file-to-test" sea binario. El comando anterior saldrá del código wit 0 en los archivos binarios, de lo contrario el código de salida sería 1.

La comprobación inversa del archivo de texto puede parecerse al siguiente comando:

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

Del mismo modo, el comando anterior saldrá con el estado 0 si el "archivo a prueba" es texto (no binario).

Lea más sobre las comprobaciones -B y -T usando el comando perldoc -f -X.

 4
Author: Onlyjob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-09 09:06:00

BSD grep

Aquí hay una solución simple para verificar un solo archivo usando BSD grep (en macOS / Unix):

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

Que básicamente comprueba si el archivo consiste en un carácter NUL.

Usando este método, para leer todos los archivos no binarios recursivamente usando la utilidad find puede hacer:

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

O incluso más simple usando solo grep:

grep -rv "\x00" .

Para la carpeta actual, use:

grep -v "\x00" *

Desafortunadamente los ejemplos anteriores no funcionarán para GNU grep, sin embargo, hay una solución.

GNU grep

Dado que GNU grep ignora caracteres NULOS, es posible buscar otros caracteres no ASCII como:

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

Nota: No funcionará para archivos que contengan solo caracteres NULOS.

 3
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-12 21:48:48

Utilice el operador de prueba de archivos incorporado de Perl -T, preferiblemente después de determinar que es un archivo plano utilizando el operador de prueba de archivos -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

Aquí está el complemento de ese conjunto:

$ 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
Author: tchrist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-18 22:42:02

Intente la siguiente línea de comandos:

file "$FILE" | grep -vq 'ASCII' && echo "$FILE is binary"
 1
Author: user1985553,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-08 16:49:00

cat+grep

Asumiendo que binario significa el archivo que contiene caracteres NULOS, este comando de shell puede ayudar:

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

O:

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

Esta es la solución para grep -q "\x00", que funciona para BSD grep, pero no para la versión GNU.

Básicamente -v para cat convierte todos los caracteres no imprimibles para que sean visibles en forma de caracteres de control, por ejemplo:

$ 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                                       |^@^@|

Donde ^@ los caracteres representan el carácter NULO. Así que una vez que estos control se encuentran caracteres, asumimos que el archivo es binario.


La desventaja del método anterior es que podría generar falsos positivos cuando los caracteres no representan caracteres de control. Por ejemplo:

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

Ver también: ¿Cómo puedo grep para todos los caracteres no ASCII.

 1
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-12 21:51:56

Saliendo La sugerencia de Bach , creo que --mime-encoding es la mejor bandera para obtener algo confiable de file.

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

Imprimirá los archivos que file cree que tienen una codificación no binaria. Puede canalizar esta salida a través de cut -d: -f1 para recortar el : encoding si solo desea los nombres de archivo.


Advertencia: como @yugr informa a continuación .doc los archivos informan una codificación de application/mswordbinary. Esto me parece un error - el tipo mime está siendo erróneamente concatenado con el codificación.

$ 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
Author: dimo414,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-23 21:31:21

Es una especie de fuerza bruta excluir archivos binarios con tr -d "[[:print:]\n\t]" < file | wc -c, pero tampoco es una conjetura heurística.

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
' _ '{}' +

El siguiente enfoque de fuerza bruta usando grep -a -m 1 $'[^[:print:]\t]' file parece bastante más rápido, sin embargo.

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
Author: vron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-21 13:01:53

También puede hacer esto aprovechando el comando diff. Compruebe esta respuesta:

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

 0
Author: tonix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-06 16:49:19

grep

Asumiendo que binario significa archivo que contiene caracteres no imprimibles (excluyendo caracteres en blanco como espacios, tabulaciones o caracteres de línea nueva), esto puede funcionar (tanto BSD como GNU):

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

Nota: GNU grep reportará un archivo que contiene solo caracteres NULOS como texto, pero funcionaría correctamente en versión BSD.

Para más ejemplos, vea: ¿Cómo puedo grep para todos los caracteres no ASCII?

 0
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-12 22:27:36