Encontrar arquivo por maquinação de padrão mágico

1

Existe um arquivo de comando bash (1) que produz o tipo de conteúdo de um arquivo de acordo com as definições de padrões correspondentes em / etc / magic e / usr / share / misc / magic.

Existe uma maneira de usar esses arquivos "mágicos" de definição de padrão como um teste para o comando "find"?

Por exemplo, existem alguns arquivos de texto e arquivos "PalmOS application"

file -b palmapp
PalmOS application

file -b readme.txt
ASCII text

Eu preciso de alguma forma de encontrar os arquivos que correspondem ao "aplicativo PalmOS" em vez de "texto ASCII", por exemplo, este é um comando ideal:

find . -magic "PalmOS*"

Existe alguma ideia para escrever um comando bash de linha única para cada teste?

    
por Gilles 19.01.2015 / 07:08

3 respostas

3

Algo ao longo das linhas de:

find . -print -exec file {} \; | grep "PalmOS"

Para arrumar o canal de saída através do awk, adicionando:

| awk '{print substr($1,2,length($1)-2)}'

    
por 19.01.2015 / 07:36
1

Não há recurso interno de find para analisar o conteúdo do arquivo, mas é possível invocar file . Usar o shell para combinar vários programas específicos de tarefas ( find para percorrer árvores de diretórios, file para analisar o conteúdo do arquivo) é a maneira Unix de fazer as coisas.

Você deseja atuar em arquivos para os quais a saída do comando file -b -- "$filename" contenha a string PalmOS application . Isso pode ser testado com o script de shell

case "$(file -b -- "$filename")" in *"PalmOS application"*) true;; *) false;; esac

Você pode usar esse script em um comando find da seguinte forma:

find . -type f -exec sh -c 'case "$(file -b "$0")" in *"PalmOS application"*) true;; *) false;; esac' {} \; -print

Substitua -print pela ação que você deseja executar (que pode ser outro -exec … ). Essa segunda ação é executada apenas se a ação anterior for verdadeira, que é quando o comando shell retorna 0 (ou seja, true).

Como alternativa, em zsh, você pode permitir que o shell faça a travessia do diretório com o ** glob . O . qualificador de glob restringe as correspondências a arquivos regulares (como -type f para find ).

for x in **/*(.); do
  [[ $(file -b -- $x) = *"PalmOS application"* ]] || continue
  …
done

No bash ≥4.3, você pode usar ** para globalização recursiva, mas é necessário ativar a opção globstar primeiro. No bash 4.0–4.2, globstar já está disponível, mas tenha em atenção que ** percorre links simbólicos para diretórios. No ksh93, use set -o globstar em vez de shopt -s globstar .

shopt -s globstar
for x in **/*; do
  [[ -f $x ]] || continue
  [[ $(file -b -- "$x") = *"PalmOS application"* ]] || continue
  …
done

Se os nomes dos arquivos não contiverem espaço em branco ou :\"' , um método alternativo será executar file nos nomes dos arquivos e analisar a saída.

find -type f |
xargs file |
sed -n 's/:.*PalmOS application.*//p' |
xargs somecommand

Se os nomes dos seus arquivos contiverem espaço em branco, mas não houver novas linhas ou vírgulas, você poderá usar o shell para fazer a análise.

find -type f |
while IFS=: read -r filename type; do
  case "$type" in
    *"PalmOS application"*)
      …;;
  esac
done
    
por 20.01.2015 / 00:54
0

Isso não usa find , mas a configuração pattern e directory produzirá os resultados solicitados pela sua pergunta:

pattern="PalmOS application"
directory=.

for f in $directory/*; do
    if [[ $(file -b $f) == "$pattern" ]]; then
        echo $f; 
    fi; 
done
    
por 19.01.2015 / 07:43