Istnieje wiele powodów, dla których wczytywanie całego pliku do obszaru wzorców może się nie powieść. Problem logiczny w pytaniu dotyczącym ostatniego wiersza jest powszechny. Jest to związane z sedcyklem linii - kiedy nie ma już linii i sednapotyka EOF, to przez nie przechodzi - przerywa przetwarzanie. I tak, jeśli jesteś na ostatniej linii i instruujesz, sedaby zdobyć kolejną, to zatrzyma się na tym miejscu i nie będzie więcej robić.
To powiedziawszy, jeśli naprawdę musisz wczytać cały plik do przestrzeni wzorców, prawdopodobnie i tak warto rozważyć inne narzędzie. Faktem jest, że sedjest to tytułowy edytor strumieniowy - jest przeznaczony do pracy z linią - lub logicznym blokiem danych - na raz.
Istnieje wiele podobnych narzędzi, które są lepiej wyposażone do obsługi pełnych bloków plików. edi exna przykład mogą zrobić wiele z tego, co sedmożna zrobić i przy podobnej składni - i wiele więcej poza tym - ale zamiast działać tylko na strumieniu wejściowym podczas przekształcania go na dane wyjściowe sed, zachowują również tymczasowe pliki kopii zapasowych w systemie plików . W razie potrzeby ich praca jest buforowana na dysk i nie poddają się gwałtownie na końcu pliku (i zwykle rzadziej implodują pod obciążeniem bufora) . Ponadto oferują wiele przydatnych funkcji, których sednie ma - w rodzaju, które po prostu nie mają sensu w kontekście strumienia - takich jak znaczniki linii, cofanie, nazwane bufory, łączenie i inne.
sedpodstawową siłą jest zdolność do przetwarzania danych natychmiast po ich odczytaniu - szybko, wydajnie i strumieniowo. Kiedy wycierasz plik, wyrzucasz go i masz tendencję do napotkania trudności z marginesami, takich jak problem z ostatnią linią, o którym wspomniałeś, przepełnienia bufora i beznadziejna wydajność - ponieważ analizowane dane wydłużają czas przetwarzania wyrażeń regularnych podczas wyliczania dopasowań rośnie wykładniczo .
Nawiasem mówiąc, jeśli chodzi o ten ostatni punkt: chociaż rozumiem, że przykładowy s/a/A/gprzypadek jest prawdopodobnie naiwnym przykładem i prawdopodobnie nie jest rzeczywistym skryptem, który chcesz zebrać w danych wejściowych, być może warto poświęcić chwilę na zapoznanie się z y///. Jeśli często globalnie zastępujesz jedną postać inną, ymoże to być bardzo przydatne. Jest to transformacja w przeciwieństwie do podstawienia i jest znacznie szybsza, ponieważ nie oznacza wyrażenia regularnego. Ten ostatni punkt może również być przydatny przy próbie zachowania i powtórzenia pustych //adresów, ponieważ nie wpływa na nie, ale może być przez nie zmieniony. W każdym razie y/a/A/jest to prostszy sposób na osiągnięcie tego samego - i możliwe są także wymiany:y/aA/Aa/ które zamieniają wszystkie wielkie / małe litery jak na linii dla siebie.
Należy również pamiętać, że opisywane zachowanie tak naprawdę nie jest tym, co powinno się wydarzyć.
Z GNU info sedw sekcji WSPÓLNIE ZGŁASZANE BŁĘDY :
POSIXLY_CORRECTZmienna jest mowa bo POSIX określa, że jeśli sednapotka EOF podczas próby Npowinno wyjść bez wyjścia, ale w wersji GNU świadomie zrywa z normą w tym przypadku. Zauważ też, że nawet jeśli zachowanie jest uzasadnione powyżej założenia, że przypadek błędu dotyczy edycji strumieniowej - a nie umieszczania całego pliku w pamięci.
W standardowych definiuje N„S zachowanie sposób:
N
Dołącz następny wiersz danych wejściowych, pomniejszając \nkońcową ewlinię, do przestrzeni wzoru, używając osadzonej \newline, aby oddzielić dołączony materiał od materiału oryginalnego. Zauważ, że bieżący numer linii zmienia się.
Jeśli nie jest dostępny następny wiersz danych wejściowych, Nczasownik polecenia rozgałęzia się do końca skryptu i kończy pracę bez rozpoczynania nowego cyklu lub kopiowania przestrzeni wzorców na standardowe wyjście.
W tej notatce pokazano kilka innych GNU-izmów - w szczególności użycie :etykiety, branch i {nawiasów kontekstowych funkcji }. Zasadniczo każde sedpolecenie, które akceptuje dowolny parametr, rozumiane jest jako ograniczenie w \newline w skrypcie. Więc polecenia ...
:arbitrary_label_name; ...
b to_arbitrary_label_name; ...
//{ do arbitrary list of commands } ...
... bardzo prawdopodobne jest nieprawidłowe działanie w zależności od sedimplementacji, która je czyta. Przenośne powinny być napisane:
...;:arbitrary_label_name
...;b to_arbitrary_label_name
//{ do arbitrary list of commands
}
To samo odnosi się do r, w, t, a, i, i c (i ewentualnie kilka bardziej, że jestem zapominając w tej chwili) . W prawie każdym przypadku można je również napisać:
sed -e :arbitrary_label_name -e b\ to_arbitary_label_name -e \
"//{ do arbitrary list of commands" -e \}
... gdzie nowa -einstrukcja \nxecution oznacza separator ewline. Więc tam, gdzie infotekst GNU sugeruje, że tradycyjne sedwdrożenie zmusiłoby cię do zrobienia :
/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N }
... raczej powinno być ...
/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N
}
... oczywiście to też nie jest prawda. Pisanie w ten sposób scenariusza jest trochę głupie. Istnieją znacznie prostsze sposoby robienia tego samego, na przykład:
printf %s\\n foo . . . . . . |
sed -ne 'H;/foo/h;x;//s/\n/&/3p;tnd
//!g;x;$!d;:nd' -e 'l;$a\' \
-e 'this is the last line'
... który drukuje:
foo
.
.
.
foo\n.\n.\n.$
.$
this is the last line
... ponieważ tpolecenie est - podobnie jak większość sedpoleceń - zależy od cyklu linii w celu odświeżenia rejestru zwrotnego i tutaj cykl linii może wykonać większość pracy. Jest to kolejny kompromis, którego dokonujesz, gdy kopiujesz plik - cykl linii nigdy się nie odświeża i tak wiele testów zachowuje się nienormalnie.
Powyższe polecenie nie ryzykuje przekroczenia zakresu danych wejściowych, ponieważ wykonuje tylko kilka prostych testów, aby zweryfikować, co czyta podczas czytania. W przypadku Hstarego wszystkie wiersze są dodawane do miejsca wstrzymania, ale jeśli linia jest zgodna /foo/, zastępuje hstare miejsce. Bufory są następnie xzmieniane, a s///próba uwarunkowania warunkowego jest podejmowana, jeśli zawartość bufora jest zgodna z //ostatnim adresowanym wzorcem. Innymi słowy, //s/\n/&/3ppróbuje zastąpić trzeci znak nowej linii w przestrzeni wstrzymania i wydrukować wyniki, jeśli przestrzeń wstrzymania jest obecnie zgodna /foo/. Jeśli to się tpowiedzie, skrypt rozgałęzia się na etykietę not delete - co powoduje, lże skrypt kończy pracę.
W przypadku, gdy oba /foo/i trzeci nowej linii, nie mogą być dopasowane razem w przestrzeni utrzymywania jednak następnie //!gzastąpi bufor Jeżeli /foo/nie jest dopasowany, lub, jeśli jest dopasowany, to zastąpić buforem jeśli \newline nie jest dopasowany (w miejsce /foo/z sama) . Ten mały, subtelny test zapobiega niepotrzebnemu zapełnianiu się bufora przez długie odcinki „nie” /foo/i zapewnia, że proces pozostanie bezproblemowy, ponieważ dane wejściowe się nie nakładają. W przypadku braku /foo/lub //s/\n/&/3pawarii bufory są ponownie zamieniane, a każda linia oprócz ostatniej jest tam usuwana.
Ta ostatnia - ostatnia linia $!d- jest prostym pokazem, w jaki sposób sedmożna wykonać skrypt odgórny, aby łatwo obsługiwać wiele spraw. Kiedy twoją ogólną metodą jest wycinanie niechcianych przypadków, zaczynając od najbardziej ogólnych i pracując w kierunku najbardziej specyficznych, wówczas przypadki brzegowe można łatwiej obsłużyć, ponieważ mogą one po prostu spaść do końca skryptu z innymi poszukiwanymi danymi i kiedy to wszystko otula cię tylko danymi, których potrzebujesz. Konieczność pobrania takich przypadków brzegowych z zamkniętej pętli może być jednak znacznie trudniejsza.
I oto ostatnia rzecz, którą muszę powiedzieć: jeśli naprawdę musisz pobrać cały plik, możesz znieść nieco mniej pracy, polegając na cyklu linii, aby to zrobić za Ciebie. Zazwyczaj należy użyć Next i next dla uprzedzona - ponieważ postęp naprzód cyklu linii. Zamiast redundantnie implementować zamkniętą pętlę w pętli - ponieważ i tak sedcykl linii jest po prostu zwykłą pętlą odczytu - jeśli Twoim celem jest tylko gromadzenie danych wejściowych bez rozróżnienia, prawdopodobnie łatwiej jest zrobić:
sed 'H;1h;$!d;x;...'
... który zbierze cały plik lub spróbuje.
uwaga dodatkowa Ni zachowanie w ostatniej linii ...
chociaż nie mam dostępnych narzędzi do przetestowania, weź pod uwagę, że Npodczas czytania i edycji w miejscu zachowuje się inaczej, jeśli edytowany plik jest plikiem skryptu do następnego odczytu.