Standardowe narzędzia Unix, jak grep
i diff
korzystać z niektórych heurystyki do klasyfikowania plików jako „tekst” lub „binarny”. (Na przykład grep
dane wyjściowe mogą zawierać wiersze podobne Binary file frobozz matches
.)
Czy istnieje wygodny test, który można zastosować w zsh
skrypcie, aby przeprowadzić podobną klasyfikację „tekstową / binarną”? (Inne niż coś takiego grep '' somefile | grep -q Binary
.)
(Zdaję sobie sprawę, że każdy taki test byłby koniecznie heurystyczny, a zatem niedoskonały).
file
jest standardowym narzędziem i może uruchamiać magię plików w celu określania typów plików zgodnie z jego najlepszymi możliwościami. Potrafi rozpoznać większość formatów tekstowych i robi całkiem przyzwoitą robotę na formatach binarnych. Jeśli wszystko, co próbujesz zrobić, to dowiedzieć się, czy plik jest tekstowy, czy nie,file
zostaną wydrukowane, np.shell script
Dla niektórych plików chciałbym sklasyfikować jako „tekst”. Czy istnieje sposób,file
aby wydrukować tylkotext
lubbinary
?cut
poleceń.file
przesyłanie potokowecut
- jasne, że brakuje miejsca, które powoduje awarię i które spowodowało większość ludzi zwraca się do litery Y zamiast litery X, ale komentarze i odpowiedzi Stéphane pokazują właściwy sposób ustalenia, czy plik jest tekstowy, czy nie.Odpowiedzi:
Jeśli poprosisz
file
o tylko typu MIME dostaniesz wiele różnych te, jaktext/x-shellscript
iapplication/x-executable
etc, ale mogę sobie wyobrazić, jeśli po prostu sprawdzić na „tekst” części należy uzyskać dobre wyniki. Np. (W-b
przypadku braku pliku wyjściowego):źródło
file
, które można pominąć niektóre formaty tekstowe:application/xml
(i podobnie jak RSS),application/ecmascript
,application/json
,image/svg+xml
, ... Można by mieć do białej listy tych.application/*
typy nie są przeznaczone do spożycia przez ludzi, nawet jeśli mogą być oparte na tekście w celu ułatwienia programowania i debugowania. Dlatego istnieje zarówno a, jaktext/xml
i anapplication/xml
. Zatem pytanie, czy uznać je za tekst, zależy od potrzeb PO.cut -d/ -f1
Innym podejściem byłoby użycie
isutf8
z kolekcji moreutils .Wychodzi z 0, jeśli plik jest poprawny UTF-8 lub ASCII, lub zwarciami, drukuje komunikat o błędzie (cisza z
-q
) i kończy z 1 w przeciwnym razie.źródło
Jeśli podoba ci się heurystyka używana przez GNU
grep
, możesz jej użyć:To wyszukuje NUL bajtów pierwszy bufor odczytu z pliku (kilka kilo bajtów dla zwykłego pliku, ale może być o wiele mniej do rury lub gniazda lub niektórych urządzeń takich jak
/dev/random
). W ustawieniach regionalnych UTF-8 oznacza to również sekwencje bajtów, które nie tworzą prawidłowych znaków UTF-8. ZakładaLC_ALL
się, że nie jest ustawiony na coś, co nie jest językiem angielskim.${1-$REPLY}
Forma pozwala na użycie go jakozsh
kwalifikator glob:wyświetli listę plików binarnych .
źródło
Możesz spróbować ustalić, czy
iconv
można odczytać plik. Jest to mniej wydajne niżfile
(co odczytuje tylko kilka bajtów od początku), ale daje bardziej wiarygodne wyniki:iconv
Zasadniczo czyni to brak operacji, ale jeśli napotka niepoprawne dane (niepoprawne UTF-8 w tym przykładzie), zablokuje się i zakończy działanie.źródło
-f
i-t
zamiast długich opcji GNU uczyniłoby go bardziej przenośnym. Pamiętaj, że wywoła „binarne” pliki, których nie może otworzyć. Nazwie puste pliki „tekstem”.iconv
. Ale-f
i-t
zwykle są lepsze.Możesz napisać skrypt, który wywołuje
file
, i użyć instrukcji case, aby sprawdzić przypadki, które Cię interesują.Na przykład
choć oczywiście może być wiele specjalnych przypadków, które są interesujące. Po sprawdzeniu
strings
kopiilibmagic
widzę około 200 przypadków, np.Niektórzy używają ciągu „tekst” jako części innego typu, np.
podobnie
script
może być częścią słowa, ale w tym przypadku nie widzę problemów. Ale skrypt powinien sprawdzać"text"
jako słowo , a nie podciąg .Dla przypomnienia,
file
wyjście nie używa dokładnego opisu, który zawsze zawierałby „skrypt” lub „tekst”. Szczególne przypadki są czymś do rozważenia. Kontynuacja skomentowała, że--mime-type
działa, podczas gdy to podejście nie, w przypadku.svg
plików. Jednak w teście widzę te wyniki dla plików svg:które wybrałem po zobaczeniu tysiąca plików, które pokazują tylko 6 z „tekstem” na wyjściu typu mime. Prawdopodobnie dopasowanie „xml” na końcu danych wyjściowych typu mime może być bardziej użyteczne, powiedzmy, niż dopasowanie „SVG”, ale użycie skryptu, aby to zrobić , spowoduje powrót do podanej tutaj sugestii.
Dane wyjściowe
file
wymagają dostrajania w obu scenariuszach i nie są w 100% niezawodne (jest mylone przez kilka moich skryptów Perla, nazywając je „danymi”).Istnieje więcej niż jedna implementacja
file
. Ten najczęściej używany działa wlibmagic
, który może być używany z różnych programów (być może nie bezpośrednio zzsh
, choćpython
może).Zgodnie z tabelą porównawczą testu plików dla powłok, Perla, Ruby i Pythona , Perl ma
-T
opcję, za pomocą której może dostarczyć te informacje. Ale nie zawiera żadnej porównywalnej funkcjizsh
.Dalsza lektura:
źródło
file
dane wyjściowe GNU dla plików svg:SVG Scalable Vector Graphics image
nie zawierają słowa tekst. Myślałem, że takie podejście byłoby lepsze niż zaakceptowana odpowiedź sprawdzania typu MIME, ale nadal nie ma niektórych typów.image/svg+xml
. Właściwie - właśnie sprawdziłem 1000 plików tak samo, tylko 6 pojawiło się jako „tekst” według samego typu MIME. Będę trzymać się skryptu, który przynajmniej można sprawić, by działał w razie potrzeby.file
ma opcję,--mime-encoding
która próbuje wykryć kodowanie pliku.Możesz użyć
file --mime-encoding | grep binary
do wykrycia, czy plik jest plikiem binarnym. Działa niezawodnie, chociaż może zostać pomylony przez pojedynczy nieprawidłowy znak w długim pliku tekstowym.Na przykład alias
cat
do następującego skryptu powłoki, aby uniknąć zniszczenia terminala przez nieumyślne otwarcie pliku binarnego:źródło
Kategorie są dowolne. Zanim odpowiesz, jak dokonać klasyfikacji, potrzebujesz (ścisłej) definicji. Aby mieć definicję, potrzebujesz celu .
Co chcesz zrobić z tą klasyfikacją?
źródło
zrobię to. Zobacz dokumentację
-B
i-T
(wyszukaj ciąg na tej stronieThe -T and -B switches work as follows
).źródło
perl -le 'print -B $ARGV[0] ? "binary" : "text"' --
może być jaśniejsze. Lub nawetperl -le 'print -B $_ ? "binary" : "text", @ARGV > 1 ? "\t$_" : "" for @ARGV' --
Przyczyniłem się do https://github.com/audreyr/binaryornot Nie ma jeszcze opakowania linii poleceń (ale), ale jest to prosta biblioteka Pythona wystarczająco łatwa do wywołania nawet z poziomu CLI. Używa dość wydajnej heurystyki, aby ustalić, czy plik jest tekstowy czy binarny.
źródło
Teraz ta odpowiedź jest już trochę stara, ale myślę, że mój przyjaciel nauczył mnie wielkiego „hacka”, aby to zrobić.
Używasz
diff
polecenia i porównujesz plik z testowym plikiem tekstowym:$ diff filetocheck testfile.txt
Teraz, jeśli
filetocheck
jest to plik binarny, wynikiem byłoby:Binary files filetocheck and testfile.txt differ
W ten sposób możesz wykorzystać
diff
polecenie i np. Napisać funkcję sprawdzającą skrypt.źródło