Jak znaleźć pliki według typu pliku?

9

Wiem, że mogę znaleźć plików za pomocą find: find . -type f -name 'sunrise'. Przykładowy wynik:

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

Wiem też, że mogę określić typ pliku pliku: file sunrise. Przykładowy wynik:

sunrise: PEM RSA private key

Ale jak mogę znaleźć pliki według typu pliku?

Na przykład my-find . -type f -name 'sunrise' -filetype=bash-script:

./astronomy/sunrise
./schedule/sunrise
Strumień
źródło
1
Nie ma --filetypeopcji dla polecenia find ani czegokolwiek innego, co powie ci o typie pliku. Jedyne, co możesz zrobić, to użyć, --exec file {} \;a następnie wpakować do niego, grep Bournejeśli szukasz skryptów bash lub grep Perljeśli szukasz skryptów Perla lub czegoś podobnego.
Nasir Riley

Odpowiedzi:

13

„Typy plików” w systemie Unix to takie rzeczy, jak zwykłe pliki, katalogi, nazwane potoki, specjalne znaki postaci, dowiązania symboliczne itp. Są to typy plików, które findmożna filtrować za pomocą tej -typeopcji.

findNarzędzie nie może być sama odróżnić „shell script”, „plik obrazu JPEG” lub jakiegokolwiek innego rodzaju zwykłego pliku . Tego typu dane można jednak rozróżnić za pomocą filenarzędzia, które sprawdza określone podpisy w samych plikach, aby określić ich typ.

Typowym sposobem oznaczania różnych typów plików danych jest ich typ MIME i filejest on w stanie określić typ MIME pliku.


Używanie fileza pomocą finddo wykrywania zwykłych plików typu MIME i używanie go do wyszukiwania tylko skryptów powłoki:

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

lub, przy użyciu bash,

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

Dodaj -name sunriseprzed, -execjeśli chcesz wykrywać tylko skrypty o tej nazwie.

Powyższe findpolecenie znajdzie wszystkie zwykłe pliki w bieżącym katalogu lub poniżej niego i dla każdego takiego pliku wywołuje krótki skrypt powłoki. Ten skrypt działa file -bina znalezionym pliku i kończy działanie z zerowym statusem wyjścia, jeśli dane wyjściowe tego polecenia zawierają ciąg /x-shellscript. Jeśli dane wyjściowe nie zawierają tego ciągu, kończy działanie z niezerowym statusem wyjścia, co powoduje findnatychmiastowe kontynuowanie następnego pliku. Jeśli okaże się, że findplik jest skryptem powłoki, polecenie przejdzie do wypisania nazwy pliku ( -printna końcu, którą można również zastąpić inną czynnością).

file -biWyjście komenda typ MIME pliku. W przypadku skryptu powłoki w systemie Linux (i większości innych systemów) byłoby to podobne

text/x-shellscript; charset=us-ascii

podczas gdy w systemach z nieco starszym wariantem filenarzędzia, może tak być

application/x-shellscript

Wspólnym bitem jest /x-shellscriptpodciąg.

Zauważ, że w systemie macOS musiałbyś użyć file -bIzamiast file -biz powodów ( -iopcja robi coś zupełnie innego). Dane wyjściowe w systemie macOS są podobne do wyników w systemie Linux.


Czy chcesz przeprowadzić jakąś akcję niestandardową na każdym skrypcie znaleziony, można to zrobić z innego -execw miejsce -printw findpoleceniach powyżej, ale byłoby również możliwe do zrobienia

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

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

Związane z:

Kusalananda
źródło
1

Możesz wykonać findna każdym znalezionym pliku, a następnie grep dla wyniku, który Cię interesuje.

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

Sugeruję, aby wzorzec wyszukiwania był jak najbardziej zbliżony do oczekiwań, aby utrzymać liczbę fałszywych trafień na niskim poziomie.

Uwaga: pliki z nowymi liniami w nazwach plików mogą powodować problemy z tym podejściem.

Rolf
źródło
0

Korzystanie perlz File::LibMagicmodułu:

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
źródło