Wie finde ich Dateien nach Dateityp?

9

Ich weiß, dass ich Dateien finden kann mit find: find . -type f -name 'sunrise'. Beispielergebnis:

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

Ich weiß auch, dass ich den Dateityp einer Datei bestimmen kann : file sunrise. Beispielergebnis:

sunrise: PEM RSA private key

Aber wie kann ich Dateien nach Dateityp finden?

Zum Beispiel my-find . -type f -name 'sunrise' -filetype=bash-script:

./astronomy/sunrise
./schedule/sunrise
Fluss
quelle
1
Es gibt keine --filetypeOption für den Befehl find oder etwas anderes, das Ihnen den Dateityp angibt. Das einzige, was Sie tun können, ist, es zu verwenden --exec file {} \;und dann weiterzuleiten, grep Bournewenn Sie nach Bash-Skripten suchen oder grep Perlwenn Sie nach Perl-Skripten oder etwas in dieser Richtung suchen.
Nasir Riley

Antworten:

13

"Dateitypen" auf einem Unix-System sind normale Dateien, Verzeichnisse, Named Pipes, spezielle Zeichendateien, symbolische Links usw. Dies sind die Dateitypen, findnach denen mit ihrer -typeOption gefiltert werden kann .

Das findDienstprogramm kann selbst nicht zwischen einem "Shell-Skript", einer "JPEG-Bilddatei" oder einem anderen Typ einer regulären Datei unterscheiden . Diese Datentypen können jedoch durch das fileDienstprogramm unterschieden werden , das bestimmte Signaturen in den Dateien selbst untersucht, um ihren Typ zu bestimmen.

Eine übliche Methode zum Beschriften der verschiedenen Datendateitypen ist der MIME-Typ , mit filedem der MIME-Typ einer Datei ermittelt werden kann.


Verwenden von filewith find, um den MIME-Typ regulärer Dateien zu erkennen und damit nur Shell-Skripte zu finden:

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

oder mit bash,

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

Fügen Sie -name sunrisevor dem hinzu, -execwenn Sie nur Skripte mit diesem Namen erkennen möchten.

Der findobige Befehl findet alle regulären Dateien im oder unter dem aktuellen Verzeichnis und ruft für jede dieser Dateien ein kurzes Inline-Shell-Skript auf. Dieses Skript wird file -bifür die gefundene Datei ausgeführt und mit einem Exit-Status von Null beendet, wenn die Ausgabe dieses Befehls die Zeichenfolge enthält /x-shellscript. Wenn die Ausgabe diese Zeichenfolge nicht enthält, wird sie mit einem Exit-Status ungleich Null beendet, wodurch findsofort mit der nächsten Datei fortgefahren wird. Wenn festgestellt wurde, dass es sich bei der Datei um ein Shell-Skript handelt, gibt der findBefehl den Pfadnamen der Datei aus (den -printam Ende, der auch durch eine andere Aktion ersetzt werden kann).

Der file -biBefehl gibt den MIME-Typ der Datei aus. Für ein Shell-Skript unter Linux (und den meisten anderen Systemen) wäre dies ungefähr so

text/x-shellscript; charset=us-ascii

Auf Systemen mit einer etwas älteren Variante des fileDienstprogramms kann dies der Fall sein

application/x-shellscript

Das gemeinsame Bit ist der /x-shellscriptTeilstring.

Beachten Sie, dass Sie unter macOS aus Gründenfile -bI anstelle von verwenden müssten (die Option macht etwas ganz anderes). Die Ausgabe unter macOS ähnelt der eines Linux-Systems.file -bi-i


Wenn Sie eine benutzerdefinierte Aktion für jedes gefundene Shell-Skript ausführen möchten, können Sie dies mit einer anderen Aktion -execanstelle der -printin den findobigen Befehlen beschriebenen tun. Dies ist jedoch auch möglich

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

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

Verbunden:

Kusalananda
quelle
1

Sie können findjede gefundene Datei ausführen und dann nach dem gewünschten Ergebnis suchen.

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

Ich schlage vor, das Suchmuster so nah wie möglich an Ihre Erwartung zu bringen, um die Anzahl der falsch positiven Übereinstimmungen niedrig zu halten.

Beachten Sie, dass Dateien mit Zeilenumbrüchen in ihren Dateinamen Probleme mit diesem Ansatz verursachen können.

Rolf
quelle
0

Verwenden perldes File::LibMagicModuls:

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
quelle