Como encontrar arquivos por tipo de arquivo?

9

Eu sei que posso encontrar arquivos usando find: find . -type f -name 'sunrise'. Resultado de exemplo:

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

Eu também sei que posso determinar o tipo de um arquivo de arquivo: file sunrise. Resultado de exemplo:

sunrise: PEM RSA private key

Mas como posso encontrar arquivos por tipo de arquivo?

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

./astronomy/sunrise
./schedule/sunrise
Fluxo
fonte
1
Não há --filetypeopção para o comando find ou qualquer outra coisa que informe o tipo de arquivo. A única coisa que você pode fazer é usar --exec file {} \;e canalizá-lo grep Bournese você estava procurando por scripts bash ou grep Perlse estava procurando por scripts Perl ou algo nesse sentido.
Nasir Riley

Respostas:

13

"Tipos de arquivos" em um sistema Unix são coisas como arquivos regulares, diretórios, pipes nomeados, arquivos especiais de caracteres, links simbólicos etc. Esses são os tipos de arquivos que findpodem ser filtrados com sua -typeopção.

O findutilitário não pode, por si só, distinguir entre um "shell script", "arquivo de imagem JPEG" ou qualquer outro tipo de arquivo comum . No entanto, esses tipos de dados podem ser diferenciados pelo fileutilitário, que analisa assinaturas específicas nos próprios arquivos para determinar seu tipo.

Uma maneira comum de rotular os diferentes tipos de arquivos de dados é pelo tipo MIME e fileé capaz de determinar o tipo MIME de um arquivo.


Usando filewith findpara detectar o tipo MIME de arquivos regulares e use-o para encontrar apenas scripts de shell:

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

ou, usando bash,

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

Adicione -name sunriseantes do -execse desejar detectar apenas scripts com esse nome.

O findcomando acima encontrará todos os arquivos regulares no diretório atual ou abaixo dele e, para cada arquivo, chame um pequeno shell script em linha. Este script é executado file -bino arquivo encontrado e sai com um status de saída zero se a saída desse comando contiver a sequência /x-shellscript. Se a saída não contiver essa sequência, ela sairá com um status de saída diferente de zero, o que fará com que findcontinue imediatamente com o próximo arquivo. Se o arquivo for considerado um shell script, o findcomando continuará produzindo o nome do caminho do arquivo ( -printno final, que também pode ser substituído por alguma outra ação).

O file -bicomando produzirá o tipo MIME do arquivo. Para um shell script no Linux (e na maioria dos outros sistemas), isso seria algo como

text/x-shellscript; charset=us-ascii

enquanto em sistemas com uma variante um pouco mais antiga do fileutilitário, pode ser

application/x-shellscript

O bit comum é a /x-shellscriptsubstring.

Observe que no macOS, você precisaria usá-lo em file -bIvez de file -bipor motivos (a -iopção faz algo bem diferente). A saída no macOS é semelhante à de um sistema Linux.


Deseja executar alguma ação personalizada em cada script de shell encontrado, você pode fazer isso com outra -execno lugar de -printnos findcomandos acima, mas também seria possível executar

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

ou, com 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
fonte
1

Você pode executar findem todos os arquivos encontrados e depois grep pelo resultado em que está interessado.

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

Sugiro que o padrão de pesquisa seja o mais próximo possível da sua expectativa de manter baixo o número de correspondências positivas positivas.

Cuidado que arquivos com novas linhas nos nomes de arquivos podem causar problemas com essa abordagem.

Rolf
fonte
0

Usando perlo File::LibMagicmódulo:

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
fonte