dotyczące przenośnego sed -e… db lub! b?

12

W tej edycji Stéphane Chazelas POSIXify (ponownie) moje sedformatowanie poprzez wstawienie -eprzerwy xpression i innej -einstrukcji xpression. Teraz mogę go zapytać, dlaczego w komentarzach, ale przypuszczam, że jest to już numer 18 tej odpowiedzi i prawie wszystkie poprzednie były już dzięki podobnym gratisom (jeśli zobaczysz usunięte komentarze, będziesz wiedział, co Mam na myśli) . Myślę też, że jestem wystarczająco blisko, aby zrozumieć, dlaczego sformułować to w sposób, który może być bardziej ogólnie przydatny. Mam nadzieję, że ...

Generalnie wolę zachować moje całkowite sed -expressions do jednego, jeśli mogę, ale mam też większą ochotę na dostosowanie się do specyfikacji tak blisko, jak to możliwe, szczególnie gdy różnica wynosi nie więcej niż a <space>i an -e. Ale nie mogę tego zrobić, jeśli nie rozumiem, dlaczego powinienem. Oto krótkie podsumowanie obecnego stanu mojego zrozumienia:

  • ' -e 'przerwa może przenośnie stanąć na sedskrypt \nprzerwie ewline w sedoświadczeniu wiersza polecenia ... Jestem wprawdzie rozmyta, dlaczego

  • nawias zamykający w sed {funkcji }musi być poprzedzony \nprzerwaniem ewline, jak podano tutaj:

    • Znak <right-brace>poprzedzony jest znakiem <newline>a i może poprzedzać go lub następować po nim <blank>znak.
  • \nprzerwa ewline podobnie jest wymagane po każdym wykorzystaniu ... a, b, c, i, r, t, w, lub :.

Ale nie rozumiem jasno, w jaki sposób definicja {funkcji }odnosi się do !operatora niebędącego operatorem. Jedyna wzmianka o operatorze negacji znajdująca się w specyfikacji:

  • Funkcja może być poprzedzona jednym lub większą liczbą !znaków, w którym to przypadku funkcja zostanie zastosowana, jeśli adresy nie wybiorą przestrzeni wzorów.

Czy oznacza to, że stosowanie dokumentu !zakłada {szelki }? Co z $!poleceniami - czy powinny być one również oddzielone ' -e 'przerwami? Czy o to chodziło, kiedy Stéphane POSIXifikował ostatnio moją odpowiedź?

Myślę, że jest to albo !operator negacji, albo bwypowiedź rancza, do której odnosi się w swojej edycji - a może jest to jednocześnie naraz - ale nie wiem i chciałbym to zrobić. Jeśli jest to tylkob oświadczenie ranczo, to wierzęd zrobiłby na jego miejscu i wyeliminować potrzebę ' -e 'przerwie, ale wolałbym być pewny zanim hazarding trzykroć POSIXified odpowiedź. Możesz pomóc?

Zrobiłem ryzykować po wszystkim , ale nie z każdej wielkiej pewności ...

mikeserv
źródło
Za pomocą b;n;:brozgałęziasz się do etykiety o nazwie ";n;:b"seds historycznej i POSIX (a GNU sed nie jest pod tym względem).
Stéphane Chazelas,
@ StéphaneChazelas - Rozumiem, :że jechałeś do domu kilka miesięcy temu. Ale nie do końca rozumiem, dlaczego drugie sedpolecenie było podobnie POSIXified .
mikeserv
1
W każdym razie specyfikacja POSIX sedjest dla mnie bardzo niejasna. W przeszłości kilkakrotnie prosiłem o wyjaśnienia, ale nie sądzę, aby w rezultacie został zaktualizowany. Dobrym testem jest wypróbowanie zestawu narzędzi dla potomków (Solaris, wywodzący się z oryginału, na którym w dużej mierze oparta jest specyfikacja POSIX).
Stéphane Chazelas,
1
@syntaxerror - wcale nie uważam, że tak jest. jeśli przeczytasz specyfikację, przekonasz się, że s///utstitutions są w stanie zaakceptować tworzenie łańcuchów za pomocą ; . rozmywa się wokół poleceń, które muszą być oddzielone znakiem nowej linii, i jak -emoże stać w tym przypadku - przynajmniej dla mnie. natknąłem się jednak na coś, sedco nie interpretuje ich dość zamiennie.
mikeserv
1
@syntaxerror - podoba mi się, ale powinieneś wiedzieć, że nie potrzebujesz ;przed nową linią - nowa linia jest w porządku. Szczerze mówiąc, to mógłby zrobić bez -ei wszystko całkowicie i po prostu zapisać plik, jak #!/bin/sedz każdego polecenia na nową linią - lub te, które nie wymagają takich ograniczników zamiast rozdzielone ;. Te, które zrobić wymagają nowej linii są zwykle te, które przyjmują dowolne wejście - :nazwy etykiet i poleceń, które odnoszą się do nich jak blub tczy zamykanie }nawiasów klamrowych dla funkcji lub rEAD i wobrzędu, które biorą args nazwy pliku. Wszystkie muszą być przenośne \n.
mikeserv

Odpowiedzi:

4

Najwyższy czas, aby na to pytanie znalazła odpowiedź i chociaż w pewnym momencie intuicyjnie wymyśliłem, jak to zrobić właściwie w każdym przypadku, dopiero niedawno udało mi się dość konkretnie to zrozumieć dzięki tekstowi w standardzie . Jest tam powiedziane dość prosto - po prostu głupio przeoczyłem to wiele razy, tak myślę.

Odpowiednie fragmenty tekstu znajdują się pod nagłówkiem ...

  • Edycja poleceń wsed :

    • Tekst argumentu składa się z jednego lub więcej wierszy. Każda osadzona \newline w tekście powinna być poprzedzona \odwrotnym ukośnikiem. Pozostałe ukośniki w tekście zostaną usunięte, a następujący znak będzie traktowany dosłownie.

    • Te ri wczasowniki aktywnego, a wflaga na srozkaz ma opcjonalny rplik (lub wplik ) parametru, oddzielone od polecenia czasownika litery lub flagi przez jeden lub więcej <blank>s; implementacje mogą pozwolić na zerową separację jako rozszerzenie.

    • Komenda czasowników innych niż {, a, b, c, i, r, t, w, :, i #można następnie ;średnikiem, opcjonalnie <blank>s, a innym czasownikiem poleceń. Jednakże, gdy sczasownik polecenia jest używany z wflagą, następujące po nim polecenie w ten sposób daje niezdefiniowane wyniki.

...w...

  • Opcje: Można określić wiele -ei -fopcje. Wszystkie polecenia należy dodać do skryptu w określonej kolejności, niezależnie od ich pochodzenia.

    • -e skrypt - Dodaj polecenia edycyjne określone przez argument opcja- skrypt na końcu skryptu poleceń edycyjnych. Argument opcja- skrypt powinien mieć takie same właściwości jak operand skryptu , opisany w sekcji OPERANDS .

    • -f plik_skryptu - Dodaj polecenia edycyjne w pliku plik_skryptu na końcu skryptu.

I ostatni w ...

  • Operandy:

    • skrypt - ciąg znaków, który będzie używany jako skrypt poleceń edycyjnych. Aplikacja nie powinna przedstawiać skryptu, który narusza ograniczenia pliku tekstowego, z wyjątkiem tego, że końcowy znak nie musi być \newline.

Tak więc, jeśli weźmiesz to w całości, ma sens, że każde polecenie, po którym opcjonalnie występuje dowolny parametr bez predefiniowanego ogranicznika (w przeciwieństwie do s d sub d repl d flagna przykład), powinno rozgraniczać na \nnieokreślonej ewline.

Można argumentować, że ; jest to predefiniowany ogranicznik, ale w takim przypadku użycie komendy ;for [aic]wymagałoby włączenia osobnego analizatora składni do implementacji specjalnie dla tych trzech komend - oddzielnego, to znaczy [:brw]na przykład od analizatora składni użytego . W przeciwnym razie implementacja musiałaby wymagać, aby w parametrze tekstowym był ; także znak odwrotnego ukośnika i od tego momentu staje się coraz bardziej skomplikowany.

Jeśli I były pisanie sedktórą chce się być zgodnych i skuteczny, to nie byłoby napisać taki osobny parser, spodziewam się - z wyjątkiem, że może [aic]powinien gen błąd składni, jeśli nie od razu następuje \newline. Ale jest to prosty problem z tokenizacją - przypadek ogranicznika końcowego jest na ogół bardziej problematyczny. Po prostu napisałbym to tak:

sed -e w\ file\\ -e one -e '...;and more commands'

...i...

sed -e a\\ -e appended\\ -e text -e '...;and more commands'

... zachowałby się bardzo podobnie, ponieważ pierwszy utworzyłby i zapisał do pliku o nazwie:

file
one

... a drugi dołączałby blok tekstu do bieżącego wiersza na wyjściu, jak ...

appended
text

... ponieważ oba będą dzielić ten sam kod parsowania dla parametru.

A jeśli chodzi o kwestię { ... }i $!problem - cóż, byłem tam daleko. Pojedyncze polecenie poprzedzone adresem nie jest funkcją, ale jest tylko poleceniem adresowanym. Prawie wszystkie polecenia - w tym { definicja funkcji } są określone do akceptacji /one/lub /one/,/two/adresów - z wyjątkiem definicji #komentarza i :etykiety . Adres może być numerem linii lub zwykłym wyrażeniem ekspresowym i można go zanegować !. Więc wszystkie ...

$!d
/address/s/ub/stitution/
5!y/d/c/

... może następować ;więcej i więcej poleceń zgodnie ze standardem, ale jeśli dla jednego adresu potrzeba więcej poleceń, a adresu tego nie należy ponownie oceniać po wykonaniu każdego polecenia, należy użyć {funkcji }takiej jak:

/address/{ s//replace addressed pattern/
           s/do other conditional/substitutions/
           s/in the same context/without/
           s/reevaluating/address/
}

... gdzie {nie może nastąpić zamknięcie w tej samej linii }i że zamknięcie }nie może nastąpić inaczej niż na początku linii. Ale jeśli po poleceniu zawartym w przeciwnym razie nie powinna występować \newline, to nie musi też występować w obrębie funkcji. Tak więc wszystkie powyższe s///wstawki - a nawet }nawias zamykający , mogą być przenośnie poprzedzone ;średnikami i dalszymi poleceniami.

\nWciąż mówię o ogranicznikach ewline, ale pytanie dotyczy zamiast tego -einstrukcji xpression, wiem. Ale te dwa są tak naprawdę jednym i tym samym, a kluczową relacją jest to, że skrypt może być dosłownym argumentem wiersza polecenia lub plikiem z jednym z nich -[ef]i że oba są interpretowane jako pliki tekstowe (które mają kończyć się na \newline), ale żadna z nich nie musi kończyć się \newline. Przez to mogę reasonbly (mam nadzieję) wywnioskować, że \0NULograniczony argumentem implikuje kończącą \newline, a wszystkie argumenty inwokacja dostać co najmniej) do \0NULogranicznika tak, wówczas powinny działać prawidłowo.

W rzeczywistości w każdym przypadku, z wyjątkiem jednego, w którym norma określa, że \nowa linia odwrotnego ukośnika powinna być wymagana, znalazłem przenośnie ...

sed -e ... -e '...\' -e '...'

... równie dobrze pracować. I w każdym przypadku - znowu, w praktyce - gdzie \nwymagany jest ewline bez ucieczki ...

sed -e '...' -e '...'

... też dla mnie zadziałało. Jedynym wyjątkiem, o którym wspomniałem powyżej, jest ...

sed -e 's/.../...\' -e '.../'

... co nie działa na żadnej implementacji w żadnym z moich testów. Jestem całkiem pewien, że sprowadza się to do wymogu dotyczącego pliku tekstowego i faktu, że s/// pochodzi z separatora, więc nie ma powodu, aby jedna instrukcja obejmowała \0NULargumenty rozdzielane ograniczeniami.

Podsumowując, oto krótki przegląd przenośnych sposobów pisania kilku rodzajów sedpoleceń:

Dla dowolnego z [aic]:

...commands;[aic]\
text embedded newline\
delimiting newline
...more;commands...

...lub...

sed -e '...commands;[aic]\' -e 'text embedded newline\' -e 'delimiting newline' -e '.;.;.'

Dla każdego, w [:rwtb]którym parametr jest opcjonalny (dla wszystkich oprócz :), ale ograniczający \newline nie jest . Zauważ, że nigdy nie miałem powodu, aby wypróbować wiele parametrów etykiety linii , które byłyby używane [:tb], ale że writing / reading do wielu linii w parametrach pliku [rw] jest zwykle akceptowany bez pytania przez seds testowałem tak długo, jak osadzony \newline jest poprzedzony \ukośnikiem odwrotnym. Mimo to standard nie określa bezpośrednio, że parametry etykiety i pliku [rw] powinny być parsowane identycznie z tekstemparametrów i nie wspomina o \newline dotyczących pierwszych dwóch, z wyjątkiem tego, że je wyznacza.

...commands;[:trwb] parameter
...more;commands...

...lub...

sed -e '[:trwb] parameter' -e '...'

... gdzie <space>powyższe jest opcjonalne dla [:tb].

I ostatni...

...;address[!]{ ...function;commands...
};...more;commands....

...lub...

sed -e '...;address[!]{ ...function;commands...' -e '};...more;commands...'

... gdzie każdy z wyżej wymienionych poleceń (z wyjątkiem :) akceptuje również co najmniej jeden adres , a które mogą być albo /wyrażeniem regularnym /lub numer linii i może być zanegowany z !, ale jeśli więcej niż jedno polecenie jest konieczne dla pojedynczej oceny adresem następnie należy użyć nawiasów ograniczających {kontekst funkcji }. Funkcja może zawierać nawet wiele \npoleceń rozdzielanych ewline, ale każda z nich musi być rozdzielana w nawiasach klamrowych, tak jak byłoby inaczej.

I tak pisze się przenośne sedskrypty.

mikeserv
źródło
2
Dlaczego nie akceptujesz własnej odpowiedzi?
Philippos,