tipo modificar leer generar fichero escribir dato con caracteristicas binarios binario archivos archivo shell unix binaryfiles

shell - leer - modificar archivo binario en c



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

¿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 los archivos binarios.


BSD grep

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

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

que básicamente verifica si el archivo contiene el carácter NUL.

Usando este método, para leer todos los archivos no binarios de forma recursiva usando la utilidad de 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" *

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

GNU grep

Como GNU grep está ignorando caracteres NULL, es posible verificar otros caracteres que no sean ASCII, como:

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

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


cat + grep

Suponiendo que binario significa el archivo que contiene caracteres NULL, 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 de 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 ^@ caracteres representan el carácter NULL. Entonces, una vez que se encuentran estos caracteres de control, suponemos 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 grep para todos los caracteres que no sean ASCII ?


grep

Suponiendo que el archivo binario significa que contiene caracteres no imprimibles (excluyendo caracteres en blanco como espacios, pestañas o nuevos caracteres de línea), esto puede funcionar (tanto BSD como GNU):

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

Nota: GNU grep informará el archivo que contiene solo caracteres NULL como texto, pero funcionaría correctamente en la versión BSD .

Para ver más ejemplos, ver: ¿Cómo grep para todos los caracteres que no sean ASCII ?



Es una especie de fuerza bruta excluir archivos binarios con tr -d "[[:print:]/n/t]" < file | wc -c 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 '' _ ''{}'' +

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

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


Pruebe la siguiente línea de comando:

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


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

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

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

Advertencia: como @yugr informa a continuación, los archivos .doc informan una codificación de la application/mswordbinary . Esto me parece un error: el tipo MIME se está concatenando erróneamente con la 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



Utilice el operador de prueba de archivo -T incorporado de Perl, preferiblemente después de comprobar que se trata de un archivo simple utilizando el operador de prueba de archivo -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


yo suelo

! grep -qI . $path

La única desventaja que puedo ver es que considerará un archivo binario vacío pero, una vez más, ¿quién decide si está mal?


Usar file utilidad, uso de muestra:

$ 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

página de manual de file


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

Podría usarse para verificar siempre que "archivo-a-prueba" sea binario. El comando anterior saldrá con el código 0 en 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 .