2012-01-29 18 views
17

Jaka jest poprawna składnia do znalezienia podłańcucha (ciąg poprzedzony i poprzedzony określonymi ciągami), który ma , a nie pasować do określonego wzorca?Sed regex i negacja podłańcuchów

Na przykład, chcę wziąć wszystkie podciągi które rozpocząć z BEGIN_, koniec z _END i podciąg pomiędzy nimi jest nie równa FOO; i zamień cały podciąg na format "(wewnętrzny podciąg)". Poniższa pasowałby:

  • BEGIN_bar_END ->(bar)
  • BEGIN_buz_END ->(buz)
  • BEGIN_ihfd8f398IHFf9f39_END ->(ihfd8f398IHFf9f39)

Ale BEGIN_FOO_END nie będzie pasować.

Grałem około z następujących, ale nie wydaje się znaleźć poprawnej składni:

sed -e 's/BEGIN_(^FOO)_END/($1)/g' 
sed -e 's/BEGIN_([^FOO])_END/($1)/g' 
sed -e 's/BEGIN_(?!FOO)_END/($1)/g' 
sed -e 's/BEGIN_(!FOO)_END/($1)/g' 
sed -e 's/BEGIN_(FOO)!_END/($1)/g' 
sed -e 's/BEGIN_!(FOO)_END/($1)/g' 
+0

Jako notatkę, gdy ma do czynienia z całych linii, można to osiągnąć za pomocą '': http://www.grymoire.com/Unix/Sed.html#uh-32 – Zenexer

Odpowiedz

27

Nie ma ogólnego operator negacji w sed IIRC ponieważ kompilacja regexes z negacji do DFAS trwa wykładniczą czasu. Można obejść ten z

'/BEGIN_FOO_END/b; s/BEGIN_\(.*\)_END/(\1)/g' 

gdzie /BEGIN_FOO_END/b oznacza: jeśli znajdziemy BEGIN_FOO_END, następnie oddział (jump) na końcu skryptu Sed.

+9

może również zostać napisany jako "sed"/BEGIN_FOO_END /! S/BEGIN _ \ (. * \) _ END/(\ 1)/g'' – potong

+2

Zwróć uwagę, że' sed '/ BEGIN_FOO_END /! S | BEGIN_ \ (.* \) _ END | (\ 1) | g'' działa, ale 'sed '| BEGIN_FOO_END |! S | BEGIN _ \ (. * \) _ END | (\ 1) | g'' nie! Najwyraźniej pozwala zastąpić inny separator niż "/" w drugiej sekcji, ale nie w pierwszej sekcji. Dziwne. – CommaToast

+1

@CommaToast Polecenie 's ///' może wykorzystywać dowolny ogranicznik; adresy nie mogą. – TheDudeAbides

2

nie wiem pretty sposób, ale zawsze można to zrobić:

$ cat file 
BEGIN_FOO_END 
BEGIN_FrOO_END 
BEGIN_rFOO_END 
$ sed '/BEGIN_FOO_END/ !{s/BEGIN_\([^_]*\)_END/(\1)/}' file 
BEGIN_FOO_END 
(FrOO) 
(rFOO) 
3

To może pracować dla Ciebie:

sed 'h;s/BEGIN_\(.*\)_END/(\1)/;/^(FOO)$/g' file 

Działa to tylko jeśli jest tylko jeden ciąg Za linię.

Dla wielu ciągów w wierszu:

sed 's/BEGIN_\([^F][^_]*\|F[^O][^_]*\|FO[^O][^_]*\|FOO[^_]\+\)_END/\(\1\)/g' file 

lub bardziej zrozumiałe:

sed 's/\(BEGIN_\)FOO\(_END\)/\1\n\2/g;s/BEGIN_\([^\n_]*\)_END/(\1\)/g;s/\n/FOO/g' file