¿Es posible usar el find
comando para encontrar todos los archivos "no binarios" en un directorio? Aquí está el problema que estoy tratando de resolver.
Recibí un archivo de archivos de un usuario de Windows. Este archivo contiene código fuente y archivos de imagen. Nuestro sistema de compilación no funciona bien con archivos que tienen terminaciones de línea de Windows. Tengo un programa de línea de comandos ( flip -u
) que cambiará las terminaciones de línea entre * nix y windows. Entonces, me gustaría hacer algo como esto
find . -type f | xargs flip -u
Sin embargo, si este comando se ejecuta contra un archivo de imagen u otro archivo multimedia binario, dañará el archivo. Me doy cuenta de que podría crear una lista de extensiones de archivo y filtrar con eso, pero prefiero tener algo que no dependa de que mantenga esa lista actualizada.
Entonces, ¿hay alguna manera de encontrar todos los archivos no binarios en un árbol de directorios? ¿O hay una solución alternativa que debería considerar?
file
utilidad en algún lugar de su secuencia de comandos / canalización para identificar si el archivo es de datos o textoRespuestas:
Usaría
file
y canalizaría la salida en grep o awk para encontrar archivos de texto, luego extraería solo la parte del nombre del archivo defile
la salida y la canalizaría en xargs.algo como:
Tenga en cuenta que el grep busca 'texto ASCII' en lugar de cualquier 'texto'; probablemente no quiera meterse con documentos de texto enriquecido o archivos de texto unicode, etc.
También puede usar
find
(o lo que sea) para generar una lista de archivos para examinar confile
:El
-d'\n'
argumento de xargs hace que xargs trate cada línea de entrada como un argumento separado, atendiendo así a los nombres de archivos con espacios y otros caracteres problemáticos. es decir, es una alternativa axargs -0
cuando la fuente de entrada no genera o no puede generar una salida separada por NULL (comofind
la-print0
opción de '). De acuerdo con el registro de cambios, xargs obtuvo la opción-d
/--delimiter
en septiembre de 2005, por lo que debería estar en cualquier distribución de Linux no antigua (no estaba seguro, por eso lo verifiqué, solo recordaba vagamente que era una adición "reciente").Tenga en cuenta que un salto de línea es un carácter válido en los nombres de archivo, por lo que se interrumpirá si algún nombre de archivo tiene un salto de línea. Para los usuarios típicos de Unix, esto es patológicamente loco, pero no se desconoce si los archivos se originaron en máquinas Mac o Windows.
También tenga en cuenta que
file
no es perfecto. Es muy bueno para detectar el tipo de datos en un archivo, pero en ocasiones puede confundirse.He usado numerosas variaciones de este método muchas veces en el pasado con éxito.
fuente
file
muestra enEnglish text
lugar deASCII text
en mi sistema Solaris, por lo que modifiqué esa parte en consecuencia. Además, lo reemplacéawk -F: '{print $1}'
con el equivalentecut -f1 -d:
.grep -I
filtros binariostext
debería ser suficiente. Esto también recogeráfile
descripciones comoASCII Java program text
oHTML document text
otroff or preprocessor input text
.ASCII text
evitar estropear los RTF.No. No hay nada especial en un archivo binario o no binario. Puede usar heurísticas como 'contiene solo caracteres en 0x01–0x7F', pero eso llamará archivos de texto con archivos binarios de caracteres no ASCII y archivos de texto de archivos binarios desafortunados.
Ahora, una vez que has ignorado eso ...
archivos zip
Si proviene de su usuario de Windows como un archivo zip, el formato zip admite marcar archivos como binarios o texto en el propio archivo. Puede usar la
-a
opción de descomprimir para prestar atención a esto y convertir. Por supuesto, vea el primer párrafo sobre por qué esto puede no ser una buena idea (el programa zip puede haber adivinado mal cuando creó el archivo).zipinfo le dirá qué archivos son binarios (b) o de texto (t) en su lista de archivos zip.
otros archivos
El comando de archivo mirará un archivo e intentará identificarlo. En particular, probablemente encontrará
-i
útil su opción (tipo MIME de salida); solo convierte archivos con texto de tipo / *fuente
Una solución general para procesar solo archivos no binarios al
bash
usarfile -b --mime-encoding
:Me puse en contacto con el autor de la utilidad de archivo y agregó un ingenioso
-00
parámetro en la versión 5.26 (lanzada el 16/04/2016, por ejemplo, en Arch y Ubuntu 16.10 actual) que imprimefile\0result\0
para múltiples archivos alimentados a la vez, de esta manera puede hacerlo p.ej:(La
awk
parte es filtrar cada archivo que no es no binario.ORS
Es el separador de salida).También se puede usar en un bucle, por supuesto:
Basado en esto y en lo anterior, creé un pequeño
bash
script para filtrar archivos binarios que utiliza el nuevo método usando el-00
parámetro defile
en versiones más nuevas y vuelve al método anterior en versiones anteriores:O aquí uno más POSIX-y, pero requiere soporte para
sort -V
:fuente
La respuesta aceptada no los encontró todos para mí. Aquí hay un ejemplo usando grep's
-I
para ignorar binarios e ignorando todos los archivos ocultos ...Aquí está en uso en una aplicación práctica: dos2unix
https://unix.stackexchange.com/a/365679/112190
fuente
La respuesta de Cas es buena, pero supone nombres de archivo sanos ; en particular se supone que los nombres de archivo no contendrán nuevas líneas.
No hay una buena razón para hacer esta suposición aquí, ya que es bastante simple (y en realidad más limpio en mi opinión) manejar ese caso correctamente también:
El
find
comando solo utiliza funciones especificadas por POSIX . El uso-exec
para ejecutar comandos arbitrarios como pruebas booleanas es simple, robusto (maneja nombres de archivo impares correctamente) y más portátil que-print0
.De hecho, POSIX especifica todas las partes del comando, excepto
flip
.Tenga en cuenta que
file
no garantiza la precisión de los resultados que devuelve. Sin embargo, en la práctica, el grepping para "texto ASCII" en su salida es bastante confiable.(Es posible que falten algunos archivos de texto, pero es muy poco probable que identifique incorrectamente un archivo binario como "texto ASCII" y lo destruya, por lo que estamos equivocados).
fuente
calls
puede ser bastante lento, por ejemplo, para videos le dirá todo sobre la codificación.-
.file
, puede tomar varios archivos como argumentos.find
comando prefijará./
a cualquier nombre de archivo pasado al comando de shell; (3) Usargrep
como prueba en unafile
salida de comando único a la vez es la única forma POSIX que puedo ver para garantizar el manejo correcto de los nombres de archivo que pueden contener nuevas líneas.file
compatible con la--mime-encoding
bandera y el--
separador, ninguno de los cuales está garantizado por POSIX .Esto encontrará todos los archivos regulares (
-type f
) en el directorio actual (o inferior) quegrep
piensa que no están vacíos ni son binarios.Se utiliza
grep -I
para distinguir entre archivos binarios y no binarios. La-I
marca y harágrep
que salga con un estado de salida distinto de cero cuando detecte que un archivo es binario. Un archivo "binario" es, de acuerdo congrep
, un archivo que contiene caracteres fuera del rango ASCII imprimible.La
-q
opción degrep
hará que se cierre con un estado de salida cero si se encuentra el patrón dado, sin emitir ningún dato. El patrón que usamos es un solo punto, que coincidirá con cualquier carácter.Si se encuentra que el archivo no es binario y contiene al menos un carácter, se imprime el nombre del archivo.
Si te sientes valiente, también puedes enchufarlo
flip -u
:fuente
Prueba esto :
Donde el argumento de
grep '[^ -~]'
es'[^<tab><space>-~]'
.Si lo escribe en una línea de comando de shell, escriba Ctrl+ Vantes Tab. En un editor, no debería haber ningún problema.
'[^<tab><space>-~]'
coincidirá con cualquier carácter que no sea texto ASCII (los retornos de carro se ignorangrep
).-L
imprimirá solo el nombre de archivo de los archivos que no coinciden-Z
generará nombres de archivo separados con un carácter nulo (paraxargs -0
)fuente
grep -P
(si está disponible)\t
está disponible. Alternativamente, usando la traducción local si el shell lo admite:$'\t'
(bash
yzsh
hacer).Solución alternativa:
El comando dos2unix convertirá los finales de línea de Windows CRLF a Unix LF y omitirá automáticamente los archivos binarios. Lo aplico recursivamente usando:
fuente
dos2unix
puede tomar varios nombres de archivo como argumento, es mucho más eficiente hacerlofind . -type f -exec dos2unix {} +
sudo find / (-type f -and -path '* / git / *' -iname 'README') -exec grep -liI '100644 \ | 100755' {} \; -exec flip -u {} \;
i. (-type f -and -path '* / git / *' -iname 'README'): busca archivos dentro de una ruta que contenga el nombre git y el archivo con el nombre README. Si conoce alguna carpeta y nombre de archivo específicos para buscar, será útil.
El comando ii.-exec ejecuta un comando en el nombre del archivo generado por find
iii. \; indica el fin del comando
iv. {} es el resultado del archivo / nombre de carpeta encontrado en la búsqueda de búsqueda anterior
v. Se pueden ejecutar varios comandos posteriormente. Al agregar -exec "comando" \; como con -exec flip -u \;
vii.grep
puede clonar este directorio de prueba y probarlo: https://github.com/alphaCTzo7G/stackexchange/tree/master/linux/findSolution204092017
respuesta más detallada aquí: https://github.com/alphaCTzo7G/stackexchange/blob/master/linux/findSolution204092017/README.md
fuente