Jeśli kwalifikujesz słowo jako dowolną sekwencję 1 lub więcej niepustych znaków, wówczas odpowiedź brzmi zdecydowanie tak, i jest również bardzo prosta. To dlatego, że [[:blank:]]*
i [^[:blank:]]*
są boolean uzupełnienia oraz - pod warunkiem wszystkie znaki w łańcuchu są kompletne - [[:blank:]]*
U [^[:blank:]]*
można opisać ewentualne ciąg w taki sam sposób .*
robi.
Jeśli w ciągu istnieje niekompletny znak lub w inny sposób nieprawidłowa sekwencja bajtów, nie można go z powodzeniem opisać od początku do końca - jak to czasami może się zdarzyć przy interpretacji ciągu w niewłaściwym kodowaniu. Aby zapewnić pełny znak na bajt w dowolnym ciągu, ustawienia narodowe C można wymusić:
LC_ALL=C sed ...
... które pozwoliłyby uniknąć problemów z opisywaniem struny od głowy do ogona za pomocą kompleksowego wzorca, takiego jak .*
lub([ ]*[^ ]*)*
W pełni komplementarny wzór może powtarzać tyle razy, ile jest to konieczne, od lewej do prawej, długości dowolnego łańcucha, aby wylądować na ostatnim możliwym wystąpieniu bez przerwy w schemacie. Jest to definitywnie zwykły język.
BRE:
sed 's/\(\([^[:blank:]]*\)[[:blank:]]*\)*/\2/'
ERE:
sed -E 's/(([^[:blank:]]*)[[:blank:]]*)*/\2/'
Obie wersje nadal będą drukować puste linie, a to dlatego, że *
gwiazda Kleene pasuje do zerowego lub więcej wystąpień wzoru. Najpierw dopasowuje zero lub więcej niepustych znaków, następnie zero lub więcej pustych znaków, a następnie zero lub więcej wystąpień zgrupowanych dopasowań, dopóki nie dopasuje ciągu w całości.
Po dopasowaniu tego wszystkiego magia dzieje się w zastępstwie - odniesienia zwracane przez grupy \1
i \2
są ostatnimi wystąpieniami każdego z nich. Tak więc po dokonaniu zamiany cały ciąg jest zastępowany tylko ostatnim wystąpieniem w wierszu zera lub więcej niepustych znaków - lub podgrupy \2
.
Oczywiście działa to na każdy możliwy ciąg - nawet pusty - co oznacza, że obie formy wypiszą znaki nowego wiersza dla wierszy zawierających tylko puste znaki lub wcale. Aby sobie z tym poradzić, możesz zrobić kilka rzeczy, ale najpierw sprawmy, aby klasa postaci była nieco łatwiejsza do pisania:
b='[:blank:]'
Teraz, aby drukować tylko wtedy, gdy wiersz zawiera jeden lub więcej niepustych znaków, możesz:
BRE:
sed -n "s/\(\([^$b]*\)[$b]*\)*/\2/;/./p"
ERE:
sed -En "/[^$b]/s/(([^$b]*)[$b]*)*/\2/p"
- Przypadek BRE - podstawienie jest zawsze wykonywane i drukowane są tylko przestrzenie wzorcowe z przynajmniej jednym pozostałym znakiem.
- Przypadek ERE - próba podstawienia jest podejmowana tylko na przestrzeni wzorów zawierającej co najmniej jeden niepusty znak.
Każda forma będzie działać z dowolną metodą - o ile składnia jest poprawna.
-n
Wyłącza wyłącznik automatyczny druk przestrzeni wzorca, a p
flagi na s///
ubstitution lub /
adres/
poleceń wypisuje jego wyniki tylko w przypadku powodzenia.
Tę samą logikę można zastosować, aby uzyskać dowolną {num}
wystąpienie, takie jak:
BRE:
sed -n "s/\([$b]*\([^$b]\{1,\}\)\)\{num\}.*/\2/p"
ERE:
sed -En "s/([$b]*([^$b]+)){num}.*/\2/p"
... gdzie num
oba wyrażenia regularne można zastąpić liczbą, aby wydrukować tylko{num}
określone wystąpienie sekwencji niepustych znaków. Stosuje się tutaj nieco inną formę, aby zapewnić, że liczba nie zostanie przekrzywiona dla wiodącej spacji w ciągu.
Zauważ, że -E
przełącznik ERE na sed
jest obsługiwany zarówno w wersji BSD, jak i GNU, chociaż nie jest to jeszcze standardowa składnia POSIX.
sed
?