Comment trouver des fichiers par type de fichier?

9

Je sais que je peux trouver des fichiers en utilisant find: find . -type f -name 'sunrise'. Exemple de résultat:

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

Je sais aussi que je peux déterminer le type de fichier d'un fichier: file sunrise. Exemple de résultat:

sunrise: PEM RSA private key

Mais comment puis-je trouver des fichiers par type de fichier?

Par exemple my-find . -type f -name 'sunrise' -filetype=bash-script:

./astronomy/sunrise
./schedule/sunrise
Flux
la source
1
Il n'y a aucune --filetypeoption pour la commande find ou toute autre chose qui vous indiquera le type de fichier. La seule chose que vous pouvez faire est d'utiliser --exec file {} \;puis de le diriger grep Bournesi vous recherchez des scripts bash ou grep Perlsi vous recherchez des scripts Perl ou quelque chose du genre.
Nasir Riley

Réponses:

13

Les "types de fichiers" sur un système Unix sont des choses comme des fichiers normaux, des répertoires, des canaux nommés, des fichiers spéciaux de caractères, des liens symboliques, etc. Ce sont les types de fichiers qui findpeuvent filtrer avec son -typeoption.

L' findutilitaire ne peut pas à lui seul faire la distinction entre un "script shell", un "fichier image JPEG" ou tout autre type de fichier standard . Ces types de données peuvent cependant être distingués par l' fileutilitaire, qui examine des signatures particulières dans les fichiers eux-mêmes pour déterminer leur type.

Une façon courante d'étiqueter les différents types de fichiers de données est leur type MIME et fileest capable de déterminer le type MIME d'un fichier.


Utiliser fileavec findpour détecter le type MIME de fichiers normaux et l'utiliser pour rechercher uniquement des scripts shell:

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

ou, en utilisant bash,

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

Ajoutez -name sunriseavant -execsi vous ne souhaitez détecter que les scripts portant ce nom.

La findcommande ci-dessus trouvera tous les fichiers normaux dans ou en dessous du répertoire courant, et pour chacun de ces fichiers, appelez un court script shell en ligne. Ce script s'exécute file -bisur le fichier trouvé et se termine avec un état de sortie nul si la sortie de cette commande contient la chaîne /x-shellscript. Si la sortie ne contient pas cette chaîne, elle se termine avec un état de sortie différent de zéro, ce qui entraîne la findpoursuite immédiate du fichier suivant. Si le fichier s'avère être un script shell, la findcommande procédera à la sortie du chemin d'accès du fichier (le -printà la fin, qui pourrait également être remplacé par une autre action).

La file -bicommande affichera le type MIME du fichier. Pour un script shell sur Linux (et la plupart des autres systèmes), ce serait quelque chose comme

text/x-shellscript; charset=us-ascii

tandis que sur les systèmes avec une variante légèrement plus ancienne de l' fileutilitaire, il peut être

application/x-shellscript

Le bit commun est la /x-shellscriptsous - chaîne.

Notez que sur macOS, vous devrez utiliser file -bIplutôt file -bique pour des raisons (l' -ioption fait quelque chose de très différent). La sortie sur macOS est similaire à celle d'un système Linux.


Souhaitez-vous effectuer une action personnalisée sur chaque script shell trouvé, vous pouvez le faire avec un autre -execà la place des -printdans les findcommandes ci-dessus, mais il serait également possible de le faire

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

En relation:

Kusalananda
la source
1

Vous pouvez exécuter findsur chaque fichier trouvé, puis rechercher le résultat qui vous intéresse.

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

Je suggère de rendre le modèle de recherche aussi proche que possible de votre attente afin de maintenir le nombre de fausses correspondances faibles.

Attention, les fichiers contenant des sauts de ligne dans leurs noms de fichiers peuvent entraîner des problèmes avec cette approche.

Rolf
la source
0

Utilisation perldu File::LibMagicmodule 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
la source