¿Cómo encontrar archivos por tipo de archivo?

9

Sé que puedo encontrar archivos utilizando find: find . -type f -name 'sunrise'. Resultado de ejemplo:

./sunrise
./events/sunrise
./astronomy/sunrise
./schedule/sunrise

También sé que puedo determinar el tipo de archivo de un archivo: file sunrise. Resultado de ejemplo:

sunrise: PEM RSA private key

Pero, ¿cómo puedo encontrar archivos por tipo de archivo?

Por ejemplo my-find . -type f -name 'sunrise' -filetype=bash-script:

./astronomy/sunrise
./schedule/sunrise
Flujo
fuente
1
No hay ninguna --filetypeopción para el comando de búsqueda o cualquier otra cosa que le diga el tipo de archivo. Lo único que puede hacer es usarlo --exec file {} \;y luego conectarlo grep Bournesi estaba buscando scripts de bash o grep Perlsi estaba buscando scripts de Perl o algo por el estilo.
Nasir Riley

Respuestas:

13

Los "tipos de archivos" en un sistema Unix son cosas como archivos normales, directorios, canalizaciones con nombre, archivos especiales de caracteres, enlaces simbólicos, etc. Estos son el tipo de archivos que findpueden filtrarse con su -typeopción.

La findutilidad por sí sola no puede distinguir entre un "script de shell", un "archivo de imagen JPEG" o cualquier otro tipo de archivo normal . Sin embargo, estos tipos de datos se pueden distinguir por la fileutilidad, que analiza firmas particulares dentro de los propios archivos para determinar su tipo.

Una forma común de etiquetar los diferentes tipos de archivos de datos es por su tipo MIME , y filees capaz de determinar el tipo MIME de un archivo.


Utilizando filecon findpara detectar el tipo MIME de archivos regulares, y utilícelo para encontrar scripts de shell:

find . -type f -exec sh -c '
    case $( file -bi "$1" ) in
        */x-shellscript*) exit 0
    esac
    exit 1' sh {} ';' -print

o, usando bash,

find . -type f \
    -exec bash -c '[[ "$( file -bi "$1" )" == */x-shellscript* ]]' bash {} ';' \
    -print

Agregue -name sunriseantes -execsi solo desea detectar scripts con ese nombre.

El findcomando anterior encontrará todos los archivos normales en o debajo del directorio actual, y para cada uno de estos archivos, llame a un breve script de shell en línea. Este script se ejecuta file -bien el archivo encontrado y sale con un estado de salida cero si la salida de ese comando contiene la cadena /x-shellscript. Si la salida no contiene esa cadena, sale con un estado de salida distinto de cero que hace findque continúe inmediatamente con el siguiente archivo. Si se encontró que el archivo era un script de shell, el findcomando procederá a generar el nombre de ruta del archivo ( -printal final, que también podría ser reemplazado por alguna otra acción).

El file -bicomando generará el tipo MIME del archivo. Para un script de shell en Linux (y la mayoría de los otros sistemas), esto sería algo así como

text/x-shellscript; charset=us-ascii

mientras que en sistemas con una variante un poco más antigua de la fileutilidad, puede ser

application/x-shellscript

El bit común es la /x-shellscriptsubcadena.

Tenga en cuenta que en macOS, debería usarlo en file -bIlugar de file -bipor razones (la -iopción hace algo bastante diferente). La salida en macOS es similar a la de un sistema Linux.


Si desea realizar alguna acción personalizada en cada script de shell encontrado, puede hacerlo con otro -execen lugar de -printen los findcomandos anteriores, pero también sería posible hacerlo

find . -type f -exec sh -c '
    for pathname do
        case $( file -bi "$pathname" ) in
            */x-shellscript*) ;;
            *) continue
        esac

        # some code here that acts on "$pathname"

    done' sh {} +

o, con bash,

find . -type f -exec bash -c '
    for pathname do
        [[ "$( file -bi "$pathname" )" != */x-shellscript* ]] && continue

        # some code here that acts on "$pathname"

    done' bash {} +

Relacionado:

Kusalananda
fuente
1

Puede ejecutar finden cada archivo encontrado y luego buscar el resultado que le interesa.

# When looking for ASCII Text
find . -type -exec file {} \; | grep "ASCII"
# or for MS Word Documents
find . -type f -exec file {} \; | grep "Microsoft Word"

Sugiero que el patrón de búsqueda sea lo más cercano posible a sus expectativas para mantener bajo el número de falsos positivos.

Tenga en cuenta que los archivos con líneas nuevas en sus nombres de archivo pueden causar problemas con este enfoque.

Rolf
fuente
0

Usando perlel File::LibMagicmódulo de:

perl -MFile::LibMagic=:easy -MFile::Find -le '
  find sub {
    print $File::Find::name if
      $_ eq "sunrise" and
      -f and
      MagicFile$_ eq "PEM RSA private key"
  }, @ARGV' -- .
Stéphane Chazelas
fuente