A las utilidades estándar de Unix les gusta grep
y diff
usan algunas heurísticas para clasificar archivos como "texto" o "binario". (Por ejemplo grep
, la salida puede incluir líneas como Binary file frobozz matches
.)
¿Existe una prueba conveniente que se pueda aplicar en un zsh
script para realizar una clasificación similar de "texto / binario"? (Aparte de algo como grep '' somefile | grep -q Binary
).
(Me doy cuenta de que cualquier prueba de este tipo sería necesariamente heurística y, por lo tanto, imperfecta).
file
es una utilidad estándar y puede ejecutar la magia de archivos para determinar los tipos de archivos lo mejor que pueda. Puede indicar la mayoría de los formatos de texto y hace un trabajo bastante decente en formatos binarios. Si todo lo que intenta hacer es averiguar si un archivo es texto o no, ese es el comando que le interesa.file
se imprimirán algunas versiones de , por ejemploshell script
, para algunos archivos que me gustaría clasificar como "texto". ¿Hay alguna manerafile
de imprimir solotext
obinary
?cut
comandos.file
salida de tuberíacut
es la solución, claro, falta un espacio que lo hace fallar y eso ha hecho la mayoría de las personas allí abordan la Y en lugar de la X, pero los comentarios y respuestas de Stéphane muestran la forma correcta de determinar si el archivo es texto o no.Respuestas:
Si solicita
file
solo el tipo mime , obtendrá muchos diferentes, comotext/x-shellscript
,application/x-executable
etc., pero me imagino que si solo verifica la parte de "texto", obtendrá buenos resultados. Por ejemplo (-b
para ningún nombre de archivo en la salida):fuente
file
, que es posible que pierda algunos formatos de texto:application/xml
(y similar como RSS),application/ecmascript
,application/json
,image/svg+xml
, ... Habría que la lista blanca aquellos.application/*
tipos no están destinados al consumo humano, incluso cuando pueden estar basados en texto para facilitar el desarrollo y la depuración. Es por eso que hay tanto atext/xml
como aapplication/xml
. Entonces, la pregunta de si considerarlos como texto depende de las necesidades del OP.cut -d/ -f1
Otro enfoque sería usar
isutf8
de la colección moreutils .Sale con 0 si el archivo es válido UTF-8 o ASCII, o cortocircuitos, imprime un mensaje de error (silencio con
-q
) y sale con 1 de lo contrario.fuente
Si te gusta la heurística utilizada por GNU
grep
, puedes usarla:Se busca NUL bytes en el primer tampón lee desde el archivo (unos kilo-bytes de un archivo normal, pero podría ser mucho menos por un tubo o de tubo o algunos dispositivos como
/dev/random
). En las configuraciones regionales UTF-8, también marca las secuencias de bytes que no forman caracteres UTF-8 válidos. AsumeLC_ALL
que no está configurado para algo donde el idioma no sea inglés.El
${1-$REPLY}
formulario le permite usarlo comozsh
calificador global:enumeraría los archivos binarios .
fuente
Puede intentar determinar si
iconv
puede leer el archivo. Esto tiene menos rendimiento quefile
(que solo lee un par de bytes desde el principio), pero le dará resultados más confiables:Esto
iconv
básicamente hace que no funcione, pero si encuentra datos no válidos (UTF-8 no válido en este ejemplo), vomitará y saldrá.fuente
-f
y en-t
lugar de las opciones largas de GNU lo haría más portátil. Tenga en cuenta que llamará "binario" a los archivos que no puede abrir. Llamará a los archivos vacíos "texto".iconv
. Pero-f
y-t
generalmente son mejores.Puede escribir un script que llame
file
y usar una declaración de caso para verificar los casos que le interesan.Por ejemplo
aunque, por supuesto, puede haber muchos casos especiales que sean de interés. Solo comprobando
strings
una copia delibmagic
, veo unos 200 casos, por ejemplo,Algunos usan la cadena "texto" como parte de un tipo diferente, por ejemplo,
igualmente
script
podría ser parte de una palabra, pero no veo problemas en este caso. Pero una secuencia de comandos debe comprobar"text"
como una palabra , no una subcadena .Como recordatorio, la
file
salida no utiliza una descripción precisa que siempre tenga "script" o "text". Los casos especiales son algo a considerar. Un seguimiento comentó que--mime-type
funciona mientras que este enfoque no lo haría, para los.svg
archivos. Sin embargo, en una prueba veo estos resultados para archivos svg:que seleccioné después de ver que mil archivos muestran solo 6 con "texto" en la salida de tipo mime. Podría decirse que hacer coincidir el "xml" al final de la salida de tipo mime podría ser más útil, por ejemplo, que hacer coincidir "SVG", pero usar un script para hacerlo lo lleva de vuelta a la sugerencia que se hace aquí.
El resultado de
file
requiere un poco de ajuste en cualquier escenario, y no es 100% confiable (varios de mis scripts de Perl lo confunden, llamándolos "datos").Hay más de una implementación de
file
. El que se usa más comúnmente hace su trabajolibmagic
, que puede usarse desde diferentes programas (quizás no directamente desdezsh
, aunquepython
puede).De acuerdo con la tabla de comparación de pruebas de archivos para shell, Perl, Ruby y Python , Perl tiene una
-T
opción que puede usar para proporcionar esta información. Pero no enumera ninguna característica comparable parazsh
.Otras lecturas:
fuente
file
, la salida de GNU para archivos svg:SVG Scalable Vector Graphics image
no contiene la palabra texto. Pensé que este enfoque sería mejor que la respuesta aceptada de verificar el tipo MIME, pero aún falta algunos tipos.image/svg+xml
. En realidad, solo verifiqué un archivo de 1000, solo 6 salieron como "texto" de acuerdo con el tipo mime solo. Seguiré con un script, que al menos se puede hacer que funcione según sea necesario.file
tiene una opción--mime-encoding
que intenta detectar la codificación de un archivo.Puede usar
file --mime-encoding | grep binary
para detectar si un archivo es un archivo binario. Funciona de manera confiable, aunque puede confundirse con un solo carácter no válido en un archivo de texto largo.Por ejemplo, alias
cat
al siguiente script de shell para evitar arruinar mi terminal al abrir inadvertidamente un archivo binario:fuente
Las categorías son arbitrarias. Antes de responder cómo hacer una clasificación, necesita una definición (estricta). Para tener una definición, necesitas un propósito .
Entonces, ¿qué quieres hacer con esa clasificación?
fuente
lo haré. Consulte la documentación para
-B
y-T
(busque en esa página la cadenaThe -T and -B switches work as follows
).fuente
perl -le 'print -B $ARGV[0] ? "binary" : "text"' --
podría ser más claro O inclusoperl -le 'print -B $_ ? "binary" : "text", @ARGV > 1 ? "\t$_" : "" for @ARGV' --
Contribuí a https://github.com/audreyr/binaryornot. Todavía no tiene un contenedor de línea de comandos, pero esta es una biblioteca simple de Python lo suficientemente fácil de llamar incluso desde la CLI. Utiliza una heurística bastante eficiente para determinar si un archivo es de texto o binario.
fuente
Ahora esta respuesta es un poco vieja, pero creo que mi amigo me enseñó un gran "truco" para hacer esto.
Utiliza el
diff
comando y comprueba tu archivo con un archivo de texto de prueba:$ diff filetocheck testfile.txt
Ahora si
filetocheck
es un archivo binario, la salida sería:Binary files filetocheck and testfile.txt differ
De esta manera, podría aprovechar el
diff
comando y, por ejemplo, escribir una función que verifique en un script.fuente