sed
Interfejs API jest prymitywny - i to z założenia. Przynajmniej pozostał prymitywny z założenia - nie wiem, czy został zaprojektowany pierwotnie od samego początku. W większości przypadków napisanie sed
skryptu, który po uruchomieniu wygeneruje inny sed
skrypt, jest w rzeczywistości prostą sprawą. sed
jest bardzo często stosowany w ten sposób przez preprocesory makr, takie jak m4
i / lub make
.
(Poniżej znajduje się wysoce hipotetyczny przypadek użycia: jest to problem zaprojektowany w celu dopasowania do rozwiązania. Jeśli wydaje ci się, że jest to rozciągnięcie, prawdopodobnie jest tak, ponieważ tak jest, ale niekoniecznie czyni go mniej ważnym.)
Rozważ następujący plik wejściowy:
cat <<"" >./infile
camel
cat dog camel
dog cat
switch
upper
lower
Gdybyśmy chcieli napisać sed
skrypt, który dołączałby słowo- literę do ogona każdego odpowiedniego słowa w powyższym pliku wejściowym tylko wtedy, gdyby można go było znaleźć w wierszu w odpowiednim kontekście , i chcieliśmy to zrobić tak efektywnie, jak to możliwe ( co powinno być naszym celem, na przykład podczas operacji kompilacji) , powinniśmy raczej unikać stosowania /
wyrażeń regularnych w /
jak największym stopniu.
Jedną z rzeczy, które moglibyśmy zrobić, jest wstępna edycja pliku w naszym systemie i nigdy nie wywoływać sed
w ogóle podczas kompilacji. Ale jeśli którekolwiek z tych słów w pliku powinno lub nie powinno być uwzględnione w oparciu o ustawienia lokalne i / lub opcje czasu kompilacji, to prawdopodobnie nie byłoby pożądaną alternatywą.
Inną rzeczą, którą moglibyśmy zrobić, to przetworzenie pliku teraz na wyrażenie regularne. Możemy stworzyć - i dołączyć do naszej kompilacji - sed
skrypt, który może wprowadzać zmiany zgodnie z numerem linii - co w dłuższej perspektywie jest zazwyczaj znacznie wydajniejszą trasą.
Na przykład:
n=$(printf '\\\n\t')
grep -En 'camel|upper|lower' <infile |
sed " 1i${n%?}#!/usr/heirloom/bin/posix2001/sed -nf
s/[^:]*/:&$n&!n;&!b&$n&/;s/://2;\$a${n%?}q"'
s/ *cat/!/g;s/ *dog/!/g
s| *\([cul][^ ]*\).*|s/.*/\1-case/p|'
... który zapisuje dane wyjściowe w postaci sed
skryptu i który wygląda jak ...
#!/usr/heirloom/bin/posix2001/sed -nf
:1
1!n;1!b1
1s/.*/camel-case/p
:2
2!n;2!b2
2!!s/.*/camel-case/p
:5
5!n;5!b5
5s/.*/upper-case/p
:6
6!n;6!b6
6s/.*/lower-case/p
q
Gdy dane wyjściowe są zapisywane w wykonywalnym pliku tekstowym na moim komputerze o nazwie ./bang.sed
i działają tak ./bang.sed ./infile
, dane wyjściowe są następujące:
camel-case
upper-case
lower-case
Teraz możesz mnie zapytać ... Dlaczego miałbym to zrobić? Dlaczego nie miałbym po prostu dopasowywać grep
zapałek? Kto w ogóle używa futerału na wielbłądy? I na każde pytanie mogłem tylko odpowiedzieć, nie mam pojęcia ... ponieważ nie mam. Przed przeczytaniem tego pytania nigdy osobiście nie zauważyłem multi-! wymaganie analizy w specyfikacji - myślę, że to całkiem fajny haczyk.
Multi-! rzecz nie od razu dla mnie sensu, choć - znaczna część sed
specyfikacji jest nastawiona prostu analizowany i po prostu generowanych sed
skryptów. Prawdopodobnie znajdziesz w tym kontekście wymagane \n
ograniczniki ewline, które [wr:bt{]
mają o wiele więcej sensu, a jeśli będziesz pamiętać o tym pomyśle, możesz lepiej zrozumieć inne aspekty specyfikacji - (takie jak :
brak akceptacji adresów i q
odmowa zaakceptować więcej niż 1) .
W przykładzie powyżej piszę z pewną formę sed
skryptu, który może tylko kiedykolwiek być odczytywane raz. Jeśli przyjrzysz się temu uważnie, zauważysz, że podczas sed
odczytywania pliku edycji przechodzi on od jednego bloku poleceń do następnego - nigdy nie rozgałęzia się ani nie kończy skryptu edycji, dopóki nie przejdzie do końca z plikiem edycji.
Uważam to za multi-! adresy mogą być bardziej przydatne w tym kontekście niż w niektórych innych, ale szczerze mówiąc, nie mogę wymyślić jednego przypadku, w którym mógłbym bardzo dobrze je wykorzystać - i to sed
bardzo często. Myślę też, że warto zauważyć, że sed
oba GNU / BSD nie radzą sobie z tym, jak podano - prawdopodobnie nie jest to aspekt specyfikacji, który jest bardzo pożądany, więc jeśli implementacja przeoczy ją, wątpię bardzo poważnie, że ich błędy @ box będą cierpieć strasznie w rezultacie.
To powiedziawszy, brak obsługi tego, jak określono, jest błędem dla dowolnej implementacji, która udaje zgodność, dlatego myślę, że należy wysłać wiadomość e-mail do odpowiednich skrzynek programistycznych i zamierzam to zrobić, jeśli nie.
!
działa jak przełącznik,/pattern/!!
jest taki sam jak/pattern/
i/pattern/!!!
jest taki sam jak/pattern/!
. Na FreeBSD wiele!
jest takich samych jak jeden.