Zgadzam się z tobą - to prawdopodobnie jest to ogólny problem. Jednak niektóre popularne narzędzia mają pewne funkcje do obsługi tego.
nl
nl, na przykład, dzieli dane wejściowe na strony logiczne, które są -deliminowane przez dwuznakowy separator sekcji . Trzy zdarzenia na linii same w sobie wskazują początek kursu , dwa ciała i jeden stopkę . Zastępuje wszystkie znalezione na wejściu puste linie wyjściowe - które są jedynymi pustymi liniami, jakie kiedykolwiek drukuje
Zmieniłem twój przykład, aby dołączyć inną sekcję i wstawić go ./infile. Wygląda to tak:
line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D
@@start
line M
line N
line O
@@end
Następnie wykonałem następujące czynności:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end$/@@/' <infile |
nl -d@@ -ha -bn -w1
nlmożna powiedzieć, aby gromadził stan na logicznych stronach, ale domyślnie tak nie jest. Zamiast tego numeruje wiersze danych wejściowych według stylów i według sekcji . Tak więc -haśrodki ponumerować wszystkie nagłówki wierszy i -bnoznacza brak linii nadwozia - jak zaczyna się w organizmie stanie.
Dopóki się tego nie nauczyłem, używałem nldowolnego wejścia, ale po uświadomieniu sobie, że nlmoże to zniekształcić dane wyjściowe zgodnie z domyślnym -deliminatorem \:, nauczyłem się być bardziej ostrożnym i zacząłem używać grep -nF ''zamiast tego nieprzetestowanego wejścia. Ale kolejną lekcją wyciągniętą tego dnia było to, że nlmożna bardzo użytecznie zastosować pod innymi względami - takimi jak ten - jeśli tylko zmodyfikujesz jego dane wejściowe tylko nieznacznie - tak jak ja sedpowyżej.
WYNIK
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
Oto kilka więcej informacji nl- czy zauważysz powyżej, jak wszystkie wiersze oprócz ponumerowanych zaczynają się od spacji? Kiedy nllinie liczb wstawiają określoną liczbę znaków do nagłówka każdego z nich. W przypadku tych wierszy nie jest numerowany - nawet puste - zawsze dopasowuje wcięcie, wstawiając ( idth -wcount + -separator len) * spacje na początku nienumerowanych linii. Pozwala to na dokładne odtworzenie treści nienumerowanej przez porównanie jej z treścią numerowaną - przy niewielkim wysiłku. Jeśli weźmiesz pod uwagę, że nlpodzieli on twoje dane wejściowe na logiczne sekcje i że możesz wstawić dowolne -sciągi na początku każdej linii, którą numeruje, to całkiem łatwo jest obsłużyć wynik:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end/@@/; t
s/^\(@@\)\{1,3\}$/& /' <infile |
nl -d@@ -ha -bn -s' do something with the next line!
'
Powyższe wydruki ...
line A
line B
1 do something with the next line!
line X
2 do something with the next line!
line Y
3 do something with the next line!
line Z
line C
line D
1 do something with the next line!
line M
2 do something with the next line!
line N
3 do something with the next line!
line O
GNU ANTYLOPA sed
Jeśli nlnie jest twoją aplikacją docelową, GNU sedmoże ewykonać dowolne polecenie powłoki w zależności od dopasowania.
sed '/^@@.*start$/!b
s//nl <<\\@@/;:l;N
s/\(\n@@\)[^\n]*end$/\1/
Tl;e' <infile
Powyżej sedzbiera dane wejściowe w przestrzeni wzorów, dopóki nie będzie wystarczające, aby pomyślnie przejść podstawienie Test i przestać bbiegać z powrotem do :labla. Kiedy tak się dzieje, wykonuje epolecenia nlwejściowe reprezentowane jako <<dokument tutaj dla całej reszty przestrzeni wzorcowej.
Przepływ pracy wygląda następująco:
/^@@.*start$/!b
- jeśli
^cała linia $ma !nie /pasuje /powyższy wzór, to jest branczerskich z skryptu i autoprinted - więc od tej chwili pracujemy tylko z serią linii, która rozpoczęła się z wzoru.
s//nl <<\\@@/
- puste
s//pole /oznacza ostatni adres, który sedpróbowano dopasować - więc to polecenie zastępuje zamiast tego całą @@.*startlinię nl <<\\@@.
:l;N
:Polecenie definiuje etykietę oddział - tu ustawić jeden o nazwie :lAbel. Polecenie Next dołącza następny wiersz danych wejściowych do obszaru wzorów, po którym \nnastępuje znak ewline. Jest to jeden z niewielu sposobów, aby uzyskać \newline w sedprzestrzeni wzorów - \npostać ewline jest pewnym ogranicznikiem dla sedder, który robił to jakiś czas.
s/\(\n@@\)[^\n]*end$/\1/
- ta
s///ubstytucja może się powieść tylko po napotkaniu początku i tylko przy pierwszym wystąpieniu linii końcowej . Będzie działał tylko na przestrzeni wzorów, w której \nnatychmiast po ostatniej linii ewline zostanie @@.*endzaznaczony sam koniec $przestrzeni wzorów. Kiedy działa, zastępuje cały dopasowany ciąg \1pierwszą \(grupą \)lub \n@@.
Tl
- te
Tgałęzie dowodzenia est na etykiecie (jeżeli istnieje) , czy udane podstawienie nie nastąpiło od czasu ostatniego linia wejściowa została wciągnięta w przestrzeń wzoru (tak jak ja w / N) . Oznacza to, że za każdym razem, gdy \newline jest dodawana do przestrzeni wzorów, która nie pasuje do ogranicznika końcowego, Tpolecenie est kończy się niepowodzeniem i rozgałęzia się z powrotem do :labla, co powoduje sedciągnięcie Nlinii zewnętrznej i zapętlanie aż do pomyślnego zakończenia .
e
Gdy podstawienie na mecz końcowego jest udany, a skrypt nie oddział z powrotem dla nieudanej Test, sedbędą execute polecenie, które looks tak:
nl <<\\@@\nline X\nline Y\nline Z\n@@$
Możesz to zobaczyć, edytując ostatnią linię, aby wyglądała Tl;l;e.
Drukuje:
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
while ... read
Ostatnim sposobem, a może najprostszym, jest użycie while readpętli, ale nie bez powodu. Powłoka - (szczególnie bashpowłoka) - jest zazwyczaj dość fatalna w obsłudze dużych ilości lub stałych strumieni. To też ma sens - zadaniem powłoki jest obsługa znaków po znaku i wywoływanie innych poleceń, które mogą obsłużyć większe rzeczy.
Ale co ważne, jego rola polega na tym, że powłoka nie może read przesadzać z danymi wejściowymi - jest określona, aby nie buforować danych wejściowych lub wyjściowych do momentu, w którym zużywa tak dużo lub nie przekazuje wystarczająco dużo czasu, aby wywoływać polecenia, których nie ma - do bajtu. readStanowi więc doskonały test wejściowy - do returninformacji o tym, czy jest jeszcze wejście i powinieneś wywołać następne polecenie, aby je odczytać - ale ogólnie nie jest to najlepsza droga.
Oto przykład, jednak, jak można wykorzystać read i inne polecenia do wejścia procesu synchronizacji:
while IFS= read -r line &&
case $line in (@@*start) :;; (*)
printf %s\\n "$line"
sed -un "/^@@.*start$/q;p";;
esac;do sed -un "/^@@.*end$/q;=;p" |
paste -d: - -
done <infile
Pierwszą rzeczą, która dzieje się dla każdej iteracji, jest readciągnięcie linii. Jeśli się powiedzie, oznacza to, że pętla nie uderzyła jeszcze w EOF, a więc w casedopasowaniu ogranicznika początkowegodo blok jest natychmiast wykonywany. W przeciwnym razie printfdrukuje $linego readi sednazywa się.
sedbędzie printować każdą linię, aż napotka znacznik początkowy - kiedy qcałkowicie wykorzysta wejście. -uPrzełącznik nbuffered jest konieczne dla GNU sedponieważ może buforować dość łapczywie inaczej, ale - według specyfikacji - inne POSIX seds powinno działać bez szczególną uwagę - tak długo, jak <infilejest zwykłym plikiem.
Gdy pierwsze sed quituje, powłoka wykonuje doblok pętli - która wywołuje kolejną, sedktóra wypisuje każdą linię, aż napotka znacznik końca . Potokuje dane wyjściowe do paste, ponieważ wypisuje numery linii w osobnych wierszach. Lubię to:
1
line M
2
line N
3
line O
pastenastępnie wkleja je razem do :postaci, a cały wynik wygląda następująco:
line A
line B
1:line X
2:line Y
3:line Z
line C
line D
1:line M
2:line N
3:line O
To tylko przykłady - tutaj można wykonać wszystko w teście lub wykonać bloki, ale pierwsze narzędzie nie może zużywać zbyt wiele danych wejściowych.
Wszystkie zaangażowane narzędzia odczytują te same dane wejściowe - i drukują wyniki - każde z osobna. Tego rodzaju rzeczy może być trudno się zawiesić - ponieważ różne narzędzia będzie buforować więcej niż inni - ale można ogólnie polegać na dd, headi sedzrobić to, co trzeba (choć dla GNU sed, trzeba CLI-switch) i zawsze powinieneś być w stanie polegać read- ponieważ z natury jest bardzo powolny . I dlatego powyższa pętla wywołuje ją tylko raz na blok wejściowy.
nlnie musi gromadzić stanu . Spójrz nanl -di sprawdzićman/infostron zawierających informacje onl„s sekcja separatora .