Czy można użyć find
polecenia, aby znaleźć wszystkie pliki „niebinarne” w katalogu? Oto problem, który próbuję rozwiązać.
Otrzymałem archiwum plików od użytkownika systemu Windows. To archiwum zawiera kod źródłowy i pliki obrazów. Nasz system kompilacji nie działa dobrze z plikami z zakończeniami linii systemu Windows. Mam program wiersza polecenia ( flip -u
), który przerzuca zakończenia linii między * nix a windows. Więc chciałbym zrobić coś takiego
find . -type f | xargs flip -u
Jeśli jednak polecenie to zostanie uruchomione dla pliku obrazu lub innego binarnego pliku multimedialnego, plik zostanie uszkodzony. Zdaję sobie sprawę, że mogę zbudować listę rozszerzeń plików i filtrować z tym, ale wolę mieć coś, co nie zależy ode mnie, aby aktualizować tę listę.
Czy istnieje sposób na znalezienie wszystkich plików niebinarnych w drzewie katalogów? A może istnieje alternatywne rozwiązanie, które powinienem rozważyć?
file
narzędzia gdzieś w skrypcie / potoku, aby ustalić, czy plik to dane, czy tekstOdpowiedzi:
Użyłem
file
i potokowałem dane wyjściowe do grep lub awk, aby znaleźć pliki tekstowe, a następnie wyodrębniłem tylko część plikufile
wyjściowego i potokowałem to do xargs.coś jak:
Zauważ, że grep wyszukuje „tekst ASCII” zamiast zwykłego „tekstu” - prawdopodobnie nie chcesz zadzierać z dokumentami Rich Text lub plikami tekstowymi Unicode itp.
Możesz także użyć
find
(lub cokolwiek innego) do wygenerowania listy plików do sprawdzenia za pomocąfile
:-d'\n'
Argument xargs sprawia xargs traktować każdą linię wejściowego jako osobny argument zatem catering dla nazwy plików ze spacjami i innymi znakami problematyczne. znaczy to alternatywąxargs -0
gdy źródłem nie, czy też nie może wytwarzać moc NULL rozdzielone (na przykładfind
„s-print0
opcja). Zgodnie z dziennikiem zmian xargs otrzymał opcję-d
/--delimiter
we wrześniu 2005 roku, więc powinien znajdować się w każdej nie starożytnej dystrybucji Linuksa (nie byłem pewien, dlatego sprawdziłem - po prostu niejasno pamiętałem, że był to „ostatni” dodatek).Zauważ, że wysuw wiersza jest prawidłowym znakiem w nazwach plików, więc to się zepsuje, jeśli w nazwach plików znajdują się źródła. Dla typowych użytkowników Uniksa jest to patologicznie szalone, ale nie jest niespotykane, jeśli pliki pochodzą z komputerów Mac lub Windows.
Pamiętaj też, że
file
nie jest to idealne. Jest bardzo dobry w wykrywaniu rodzaju danych w pliku, ale czasami może się zdezorientować.W przeszłości z powodzeniem korzystałem z wielu odmian tej metody.
źródło
file
wyświetla sięEnglish text
raczej niżASCII text
w moim systemie Solaris, więc odpowiednio zmodyfikowałem tę część. Ponadto zastąpiłemawk -F: '{print $1}'
odpowiednikiemcut -f1 -d:
.grep -I
filtry binarnetext
powinno wystarczyć. Spowoduje to również pobraniefile
opisów takich jakASCII Java program text
lubHTML document text
lubtroff or preprocessor input text
.ASCII text
aby uniknąć pomieszania RTF.Nie. Nie ma nic specjalnego w pliku binarnym lub niebinarnym. Możesz użyć heurystyki, np. „Zawiera tylko znaki w 0x01–0x7F”, ale to wywoła pliki tekstowe z plikami binarnymi bez znaków ASCII i pechowymi plikami tekstowymi.
Teraz, gdy zignorujesz to ...
pliki zip
Jeśli pochodzi od użytkownika systemu Windows jako plik zip, format zip obsługuje oznaczanie plików jako plików binarnych lub tekstowych w samym archiwum. Możesz użyć
-a
opcji rozpakowania, aby zwrócić na to uwagę i przekonwertować. Oczywiście zapoznaj się z pierwszym akapitem, aby dowiedzieć się, dlaczego nie jest to dobry pomysł (program zip mógł pomylić się podczas tworzenia archiwum).zipinfo powie ci, które pliki są binarne (b) lub tekstowe (t) na liście zipfile.
inne pliki
Polecenie file sprawdzi plik i spróbuje go zidentyfikować. W szczególności prawdopodobnie
-i
przydatna będzie opcja (wyjściowy typ MIME); konwertuj tylko pliki typu text / *źródło
Ogólne rozwiązanie do przetwarzania plików innych niż binarne
bash
przy użyciufile -b --mime-encoding
:Skontaktowałem się z autorem narzędzia do plików i dodał on sprytny
-00
parametr w wersji 5.26 (wydany 2016-04-16, jest np. W obecnym Archu i Ubuntu 16.10), który drukujefile\0result\0
dla wielu dostarczonych do niego plików jednocześnie, w ten sposób możesz to zrobić na przykład:(
awk
Częścią jest odfiltrowanie każdego pliku, który nie jest binarny.ORS
Jest separatorem wyjściowym.)Oczywiście można go również używać w pętli:
Na podstawie tego i poprzedniego stworzyłem mały
bash
skrypt do odfiltrowywania plików binarnych, który wykorzystuje nową metodę przy użyciu-00
parametrufile
w nowszych wersjach i wraca do poprzedniej metody w starszych wersjach:Lub tutaj bardziej POSIX-y, ale wymaga obsługi
sort -V
:źródło
Przyjęta odpowiedź nie znalazła dla mnie wszystkich. Oto przykład użycia grep
-I
do ignorowania plików binarnych i ignorowania wszystkich ukrytych plików ...Tutaj jest używany w praktycznej aplikacji: dos2unix
https://unix.stackexchange.com/a/365679/112190
źródło
Odpowiedź Cas jest dobra, ale zakłada rozsądne nazwy plików; w szczególności zakłada się, że nazwy plików nie będą zawierać nowych linii.
Nie ma powodu, aby przyjmować to założenie, ponieważ jest to całkiem proste (i moim zdaniem czystsze), aby poprawnie obsługiwać tę sprawę:
find
Komenda czyni korzystanie jedynie z POSIX określonych cech . Używanie-exec
do uruchamiania dowolnych poleceń jako testów logicznych jest proste, niezawodne (poprawnie obsługuje nieparzyste nazwy plików) i bardziej przenośne niż-print0
.W rzeczywistości wszystkie części polecenia są określone przez POSIX, z wyjątkiem
flip
.Pamiętaj, że
file
nie gwarantuje to dokładności wyników, które zwraca. Jednak w praktyce grepowanie dla „tekstu ASCII” na wyjściu jest dość niezawodne.(Być może brakuje niektórych plików tekstowych, ale jest bardzo mało prawdopodobne, aby nieprawidłowo zidentyfikować plik binarny jako „tekst ASCII” i zmienić go w błąd - dlatego popełniamy błąd z ostrożnością.)
źródło
calls
może być dość powolny, np. W przypadku filmów wideo opowie ci wszystko o kodowaniu.-
.file
, może ono przyjmować wiele plików jako argumenty.find
polecenie będzie poprzedzać./
dowolną nazwę pliku przekazywaną do polecenia powłoki; (3) Używaniegrep
jako testu pojedynczegofile
wyjścia polecenia jest jedynym sposobem POSIX, jaki widzę, aby zagwarantować poprawną obsługę nazw plików, które mogą zawierać znaki nowej linii.file
obsługuje--mime-encoding
flagę i--
separator, z których żaden nie jest gwarantowany przez POSIX .Spowoduje to znalezienie wszystkich zwykłych plików (
-type f
) w bieżącym katalogu (lub poniżej), któregrep
mogą być niepuste i binarne.Służy
grep -I
do rozróżniania plików binarnych i niebinarnych.-I
Flag i spowoduje, żegrep
do wyjścia ze stanem wyjściowym niezerową, gdy wykryje, że plik jest binarny. Plik „binarny” jest, zgodnie z tymgrep
, plikiem zawierającym znak spoza zakresu drukowalnego ASCII.-q
Opcjagrep
spowoduje to, aby wyjść z kodem zerowym, jeśli dany wzorzec zostanie znaleziony, bez emitowania żadnych danych. Wzór, którego używamy, to pojedyncza kropka, która będzie pasować do dowolnego znaku.Jeśli okaże się, że plik nie ma charakteru binarnego i jeśli zawiera co najmniej jeden znak, drukowana jest nazwa pliku.
Jeśli czujesz się odważny, możesz również podłączyć
flip -u
do niego:źródło
Spróbuj tego :
Gdzie argument
grep '[^ -~]'
jest'[^<tab><space>-~]'
.Jeśli wpiszesz go w linii poleceń powłoki, wpisz Ctrl+ Vprzed Tab. W edytorze nie powinno być problemu.
'[^<tab><space>-~]'
dopasuje dowolny znak, który nie jest tekstem ASCII (znaki powrotu karetki są ignorowane przezgrep
).-L
wypisze tylko nazwę pliku, który nie pasuje-Z
wyświetli nazwy plików oddzielone znakiem null (dlaxargs -0
)źródło
grep -P
(jeśli jest dostępny)\t
jest dostępny. Alternatywnie, stosując tłumaczenie lokalizacji jeśli podpory powłoki w jakiej:$'\t'
(bash
izsh
robią).Alternatywne rozwiązanie:
Polecenie dos2unix konwertuje zakończenia linii z Windows CRLF na Unix LF i automatycznie pomija pliki binarne. Stosuję go rekurencyjnie, używając:
źródło
dos2unix
jako argument można przyjąć wiele nazw plików, jest to o wiele bardziej wydajnefind . -type f -exec dos2unix {} +
sudo find / (-type f -and -path '* / git / *' -iname 'README') -exec grep -liI '100644 \ | 100755' {} \; -exec flip -u {} \;
i. (-type f -and -path '* / git / *' -iname 'README'): wyszukuje pliki w ścieżce zawierającej nazwę git i plik o nazwie README. Jeśli znasz jakiś konkretny folder i nazwę pliku do wyszukania, przyda się.
ii.-exec uruchamia polecenie na nazwie pliku wygenerowanej przez find
iii. \; wskazuje koniec polecenia
iv. {} jest wyjściem pliku / nazwy folderu znalezionego podczas poprzedniego wyszukiwania wyszukiwania
v.Następnie można uruchamiać wiele poleceń. Dołączając polecenie -exec „command” \; na przykład z -exec flip -u \;
vii.grep
możesz sklonować ten katalog testowy i wypróbować go: https://github.com/alphaCTzo7G/stackexchange/tree/master/linux/findSolution204092017
bardziej szczegółowa odpowiedź tutaj: https://github.com/alphaCTzo7G/stackexchange/blob/master/linux/findSolution204092017/README.md
źródło