Co oznacza: a; $! N; w rozkazie sed?

11
$ (echo hello; echo there) | sed ':a;$!N;s/\n/string/;ta'
hellostringthere

Powyższe sedpolecenie zastępuje nowy znak wiersza ciągiem „ciąg”. Ale nie znam znaczenia :a;$!N;s/\n/string/;tapojedynczych cytatów. Znam środkową część s/\n/string/. Ale nie znam funkcji pierwszej ( :a;$!N;) i ostatniej ( ta) części.

Avinash Raj
źródło
2
Proszę spojrzeć na stackoverflow.com/questions/1251999/... .
xiaodongjie
A co z ostatnią częścią?
Avinash Raj
Polecenie „t” rozgałęzia się do nazwanej etykiety, jeśli ostatnia komenda zastępcza zmodyfikowała przestrzeń wzorców.
xiaodongjie

Odpowiedzi:

17

Są to, co prawda, tajemnicze sedpolecenia. W szczególności (z man sed):

: etykieta
         Etykieta dla poleceń b i t.

etykieta t
         Jeśli as /// dokonał pomyślnego podstawienia od ostatniego odczytu linii wejściowej i od ostatniego polecenia t lub T, to należy przejść do etykiety; jeśli etykieta zostanie pominięta, przejdź do końca skryptu.

n N Odczytaj / dodaj następny wiersz danych wejściowych do obszaru wzorów.

Tak więc skrypt, który opublikowałeś, można podzielić na (dodane spacje dla czytelności):

sed ':a;  $!N;  s/\n/string/;  ta'
     ---  ----  -------------  --
      |     |        |          |--> go back (`t`) to `a`
      |     |        |-------------> substitute newlines with `string`
      |     |----------------------> If this is not the last line (`$!`), append the 
      |                              next line to the pattern space.
      |----------------------------> Create the label `a`.

Zasadniczo to, co to robi, można zapisać w pseudokodzie jako

while (not end of line){
    append current line to this one and replace \n with 'string'
}

Możesz to zrozumieć nieco lepiej dzięki bardziej złożonemu przykładowi wprowadzania:

$ printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;$!N;s/\n/string/;ta'
line1stringline2stringline3stringline4stringline5

Nie jestem do końca pewien, dlaczego !$jest to potrzebne. O ile mogę stwierdzić, możesz uzyskać tę samą moc wyjściową

printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;N;s/\n/string/;ta'
terdon
źródło
1
! $ To nie pasować do ostatniej nowej linii, IMO.
Braiam
@Braiam nie zbyt pewni, że to $!nie !$. Jednak może być !Ni nie $!.
terdon
Próbowałem parsować stronę texinfo, ale nie znalazłem odniesień do żadnej !Nlub $!. Tak więc nadal myślę, że to, czy ostatnia linia to nowa linia, czy EOF.
Braiam
4
Staram się myśleć o $!„zasięgu” adresu z operatorem dopełniania Postfiksa - więc $!N(rób to Nwszędzie oprócz adresu $) jest tak naprawdę taką samą składnią jak coś podobnego m,n!d(usuwaj wszystko oprócz wierszy mdo n).
steeldriver
:jest analogiem do gotoetykiety i faktycznie :był goto label w skorupie Thompsona, więc byłoby znane ludziom w ciągu dnia za pomocą zarówno sed, jak i powłoki Thompson
Sergiy Kolodyazhnyy
0

Ja po tej odpowiedzi, ponieważ widzę sporo zamieszania na temat , dlaczego ostatnia linia jest wyłączona podczas wykonywania N(poprzez adresowania ciąg linii $!) i dlatego, że PO zmieszał o znaczeniu :a;$!N; w a sed polecenia , nie tylko w tym jednym konkretnym on pisał .

Cóż, korzyść z używania $!Nzamiast Nnie jest oczywista w proponowanych przykładach (przez OP i @terdon), ponieważ w ostatnim wierszu po poleceniu nie jest wykonywane polecenie „ważne” (kontynuuj czytanie) N. (Rzeczywiście, wynik jest taki sam, jeśli ktoś usunie ten adres linii.)

W bardziej złożonym przykładzie (na przykład zamień this sentencew pliku, gdzie dwa słowa pojawiają się czasami w jednej linii, a innym razem w dwóch liniach), wykluczenie ostatniego wiersza Npolecenia może być kluczowe! Jeśli ostatni wiersz nie jest wykluczony, po wykonaniu Nna nim seduderza EOFi kończy natychmiast, uniemożliwiając wykonanie wszystkich kolejnych poleceń (także poleceń rozgałęziających, a mianowicie ti b).

W pokazanych zbyt uproszczonych przykładach możemy bezpiecznie usunąć $!i pozwolić na sedniepowodzenie wykonania Ni powrotu, ponieważ przerwane spolecenie nie zrobiłoby nic, gdyby zostało wykonane, ponieważ nie można \ngo dopasować.

Enrico Maria De Angelis
źródło