Chcę usunąć końcowe białe znaki ze wszystkich plików w rekurencyjnej hierarchii katalogów. Używam tego:
find * -type f -exec sed 's/[ \t]*$//' -i {} \;
Działa to, ale usuwa również końcowe białe znaki z znalezionych plików binarnych, co jest niepożądane.
Jak mam powiedzieć, find
żeby unikać uruchamiania tego polecenia na plikach binarnych?
file
które mogą sprawdzać dane.Odpowiedzi:
Możesz spróbować użyć
file
polecenia Unix, aby zidentyfikować pliki, których nie chcesz, ale myślę, że lepiej byłoby, jeśli wyraźnie określisz, które pliki chcesz trafić, a nie te, których nie chcesz.aby uniknąć przechodzenia do plików kontroli źródła, możesz chcieć czegoś takiego
W zależności od powłoki możesz, ale nie potrzebujesz, odwrotnych ukośników.
źródło
-i
opcji sed . Trudno jest napisać przenośne polecenie powłoki, prawda?Można to zrobić w wierszu polecenia.
źródło
Najprostszą i najbardziej przenośną odpowiedzią jest uruchomienie tego:
Wyjaśnię, dlaczego poniżej, gdzie również pokazuję, jak to zrobić za pomocą wiersza polecenia, a także jak radzić sobie z plikami tekstowymi trans-ASCII, takimi jak ISO-8859-1 (Latin-1) i UTF-8, które również nie mają -ASCII w nich białe znaki.
Reszta historii
Problem polega na tym, że find (1) nie obsługuje
-T
operatora testowania plików, ani nie rozpoznaje kodowania, jeśli tak - co absolutnie musisz wykryć UTF-8, de facto standardowe kodowanie Unicode.Co możesz zrobić, to uruchomić listę nazw plików przez warstwę, która wyrzuca pliki binarne. Na przykład
Jednak teraz masz problem z białymi spacjami w nazwach plików, więc musisz opóźnić to z zerowym zakończeniem:
Inną rzeczą, którą możesz zrobić, to nie używać,
find
alefind2perl
ponieważ Perl-T
już rozumie :A jeśli chcesz, aby Perl założył, że jego pliki znajdują się w UTF-8, użyj
Lub możesz zapisać wynikowy skrypt w pliku i edytować go. Naprawdę naprawdę nie powinieneś uruchamiać
-T
testowania plików na żadnym starym pliku, ale tylko na tych, które są zwykłymi plikami, jak określa to po raz pierwszy-f
. W przeciwnym razie ryzykujesz otwarcie ofert specjalnych urządzeń, blokowanie na FIFO itp.Jeśli jednak masz zamiar to zrobić, równie dobrze możesz całkowicie pominąć sed (1). Po pierwsze, jest bardziej przenośny, ponieważ wersja sed (1) POSIX nie rozumie
-i
, podczas gdy wszystkie wersje Perla tak. Ostatnie wersje sed z miłością zawłaszczyły bardzo przydatną-i
opcję od Perla, w którym po raz pierwszy pojawia się ti.Daje to również możliwość naprawy wyrażenia regularnego. Naprawdę powinieneś używać wzorca, który pasuje do jednej lub więcej końcowych białych spacji, a nie tylko ich zero, w przeciwnym razie będziesz działać wolniej z niepotrzebnego kopiowania. To jest to:
Powinien być
Jednak, jak uzyskać sed (1), aby zrozumieć, że wymaga rozszerzenia nie-POSIX, zwykle albo
-R
dla Uniksów Systemu like, jak Solaris lub Linux, lub-E
dla BSD, takich jak OpenBSD lub MacOS. Podejrzewam, że jest to niemożliwe w systemie AIX. Wiesz, łatwiej jest napisać przenośną powłokę niż przenośny skrypt powłoki.Ostrzeżenie o 0xA0
Chociaż są to jedyne poziome znaki białych znaków w ASCII, zarówno ISO-8859-1, a tym samym także Unicode, mają PRZESTRZEŃ BEZ PRZERWU w punkcie kodowym U + 00A0. Jest to jeden z dwóch najlepszych znaków spoza ASCII znalezionych w wielu korpusach Unicode, a ostatnio widziałem, jak wielu ludzi łamie kod wyrażenia regularnego, ponieważ o tym zapomnieli.
Dlaczego więc tego nie zrobisz:
Jeśli możesz mieć UTF-8 pliki do czynienia z, dodać
-CSD
, i jeśli używasz Perl v5.10 lub większy, można użyć\h
do poziomego spacji i\R
dla rodzajowego LINEBREAK, która obejmuje\r
,\n
,\r\n
,\f
,\cK
,\x{2028}
, i\x{2029}
:Będzie to działać na wszystkich plikach UTF-8 bez względu na ich łamanie linii, eliminując końcowe białe znaki (właściwość znaku Unicode
HorizSpace
), w tym nieprzyjemną PRZESTRZEŃ BEZ PRZERWU, która występuje przed łamaniem linii Unicode (włączając kombinacje CRLF) na końcu każdej linii.Jest także o wiele bardziej przenośny niż wersja sed (1), ponieważ istnieje tylko jedna implementacja perla (1), ale wiele z sed (1).
Główny problem, jaki, jak widzę, nadal istnieje w przypadku find (1), ponieważ w niektórych naprawdę opornych systemach (wiesz, kim jesteś, AIX i Solaris) nie zrozumie
-print0
dyrektywy nadkrytycznej . Jeśli taka jest Twoja sytuacja, powinieneś po prostu użyćFile::Find
modułu bezpośrednio z Perla i nie używać żadnych innych narzędzi Uniksa. Oto czysta wersja kodu Perla, która nie polega na niczym innym:Jeśli korzystasz tylko z plików tekstowych ASCII lub ISO-8859-1, to dobrze, ale jeśli używasz plików ASCII lub UTF-8, dodaj
-CSD
przełączniki w wywołaniu wewnętrznym Perla.Jeśli masz mieszane kodowanie wszystkich trzech ASCII, ISO-8859-1 i UTF-8, obawiam się, że masz inny problem. :( Będziesz musiał ustalić kodowanie dla poszczególnych plików i nigdy nie ma dobrego sposobu, aby zgadnąć.
Biała spacja Unicode
Dla przypomnienia, Unicode ma 26 różnych białych znaków. Można skorzystać z unichars narzędzia wąchać te obecnie. Tylko pierwsze trzy poziome znaki białych znaków są prawie zawsze widoczne:
źródło
GNU grep jest całkiem dobry w identyfikowaniu, czy plik jest binarny czy nie. Poza Solaris jestem pewien, że istnieją inne platformy, które nie są domyślnie instalowane z GNU grep, ale podobnie jak Solaris, jestem pewien, że możesz go zainstalować.
Jeśli jesteś w Solaris, można wymienić
grep
z/opt/csw/bin/ggrep
.Te
grep
flagi wykonaj następujące czynności:l
tylko listy nazw dla plików pasujące,R
jest rekurencyjne,I
pasuje tylko pliki tekstowe (ignoruje pliki binarne) iP
jest dla składni wyrażeń regularnych Perl-kompatybilne.Część Perla modyfikuje plik na miejscu, usuwając wszystkie spacje / tabulatory końcowe.
Wreszcie: jeśli UTF8 stanowi problem, odpowiedź tchrista w połączeniu z moją powinna być wystarczająca, pod warunkiem, że
grep
twoja kompilacja została zbudowana z obsługą UTF8 (zwykle opiekunowie pakietów starają się jednak zapewnić taką funkcjonalność).źródło