Z bash
powłoką w pliku z wierszami podobnymi do poniższych
first "line"
<second>line and so on
Chciałbym, aby zastąpić jeden lub więcej wystąpień "line"\n<second>
z other characters
i uzyskanie za każdym razem:
first other characters line and so on
Więc muszę zastąpić ciąg zarówno znakami specjalnymi, jak "
i <
znakiem nowej linii.
Po przeszukaniu innych odpowiedzi stwierdziłem, że sed
można zaakceptować znaki nowej linii po prawej stronie polecenia (czyli other characters
ciąg znaków), ale nie po lewej.
Czy istnieje sposób (prostszy niż ten ), aby uzyskać ten wynik za pomocą sed
lub grep
?
text-processing
sed
grep
newlines
BowPark
źródło
źródło
\n
oświadczenie ewline zrobić dlatego pytam. ludzie rzadko pytają, czy mogą zrobićs//\n/
tak, jak ty z GNUsed
, chociaż większość innychsed
odrzuca tę ucieczkę po prawej stronie. mimo to funkcja\n
ucieczki będzie działać po lewej stronie w dowolnym POSIXsed
- ie i można je przenośnie tłumaczyć tak,y/c/\n/
jakby miało to ten sam efekt, cos/c/\n/g
nie zawsze jest tak przydatne.Odpowiedzi:
Trzy różne
sed
polecenia:Wszystkie trzy opierają się na podstawowym
s///
poleceniu dotyczącym upodstytucji:Wszyscy oni również starają się zachować ostrożność w obsłudze ostatniego wiersza, ponieważ
sed
zwykle różnią się wydajnością w przypadku krawędzi. To jest znaczenie$!
adresu odpowiadającego każdej linii, która!
nie jest$
ostatnia.Wszyscy oni również używają
N
polecenia ext, aby dołączyć następny wiersz wejściowy do przestrzeni wzorów po\n
znaku ewline. Każdy, ktosed
przez jakiś czas\n
grał, nauczy się polegać na postaci ewline - ponieważ jedynym sposobem na zdobycie takiego jest wyraźne umieszczenie go tam.Wszystkie trzy podejmują próbę odczytania jak najmniejszej ilości danych wejściowych przed podjęciem działania -
sed
działają tak szybko, jak to możliwe i nie muszą czytać całego pliku wejściowego przed wykonaniem tej czynności.Chociaż robią wszystko
N
, wszystkie trzy różnią się metodami rekurencji.Pierwsze polecenie
Pierwsze polecenie wykorzystuje bardzo prostą
N;P;D
pętlę. Te trzy polecenia są wbudowane w dowolny kompatybilny z POSIXsed
i ładnie się uzupełniają.N
- jak już wspomniano, dołączaN
linię wejściową ext do przestrzeni wzorów po wstawionym\n
ograniczniku ewline.P
- jakp
; toP
rints wzorzec-przestrzeń - ale tylko do pierwszego występującego\n
charakteru ewline. I tak, biorąc pod uwagę następujące dane wejściowe / polecenia:printf %s\\n one two | sed '$!N;P;d'
sed
P
rints tylko jeden . Jednak z ...D
- jakd
; toD
eletes wzorzec-przestrzeń i zaczyna kolejną linię cyklu. W przeciwieństwie dod
,D
usuwa tylko do pierwszego występującego\n
ewline w przestrzeni wzorca. Jeśli po\n
znaku ewline w przestrzeni wzorcowej znajduje się więcej przestrzeni ,sed
rozpoczyna się następny cykl linii od tego, co pozostało. Jeżelid
w poprzednim przykładzie zostały zastąpione zD
, na przykład,sed
byP
rukuj zarówno jeden i dwa .To polecenie jest powtarzane tylko dla wierszy, które nie pasują do
s///
instrukcji ubstitution. Ponieważs///
ubstitution usuwa\n
dodaną ewlineN
, nigdy nie pozostaje nic posed
D
usunięciu przestrzeni wzorców.Testy można wykonać w celu zastosowania
P
i / lubD
wybiórczo, ale są też inne polecenia, które lepiej pasują do tej strategii. Ponieważ rekurencji jest realizowany obsłużyć kolejne linie, które pasują tylko część reguły zastępczej, kolejne sekwencje linii pasujących oba końce nas///
ubstitution nie działają dobrze .:Biorąc pod uwagę ten wkład:
... drukuje ...
Poradzi sobie jednak
...w porządku.
Drugie polecenie
To polecenie jest bardzo podobne do trzeciego. Obaj stosują etykietę
:b
ranch /t
est (jak pokazano również w odpowiedzi Joesepha R. tutaj ) i powracają do niej pod pewnymi warunkami.-e :n -e
- przenośnesed
skrypty ograniczają:
definicję etykiety za pomocą\n
ewline lub nowej wbudowanej-e
instrukcji xecution .:n
- definiuje etykietę o nazwien
. To może być zwrócone w dowolnym momencie albobn
albotn
.tn
-t
komenda est powraca do określonej etykiety (lub, jeśli nie została podana, kończy działanie skryptu dla bieżącego cyklu linii), jeśli jakakolwieks///
ubstitution od czasu zdefiniowania etykiety lub ostatniego wywołaniat
ests zakończyła się powodzeniem.W tym poleceniu następuje rekurencja dla pasujących linii. Jeśli z
sed
powodzeniem zastąpi wzorzec innymi znakami ,sed
powraca do:n
etykiety i próbuje ponownie. Jeślis///
nie zostanie wykonanased
umstitution, automatycznie drukuje się przestrzeń wzorcowa i rozpoczyna się następny cykl linii.Zwykle lepiej radzi sobie z kolejnymi sekwencjami. Tam, gdzie ostatni zawiódł, wyświetla się:
Trzecie polecenie
Jak wspomniano, logika tutaj jest bardzo podobna do ostatniej, ale test jest bardziej wyraźny.
/"$/bn
- to jestsed
test. Ponieważb
polecenie ranch jest funkcją tego adresu,sed
będzieb
rancho tylko:n
po\n
dodaniu ewline, a przestrzeń wzorców nadal kończy się"
podwójnym cudzysłowem.Jest tak mało zrobione pomiędzy
N
ib
jak to możliwe - w ten sposóbsed
można bardzo szybko zebrać dokładnie tyle danych, ile jest to konieczne, aby upewnić się, że poniższy wiersz nie pasuje do twojej reguły. Ws///
różni się tutaj tym, że zatrudnia ubstitutiong
skroniowe flagi - i tak to zrobi wszelkie niezbędne zamienniki naraz. Biorąc pod uwagę identyczne dane wejściowe, polecenie wypisuje identycznie do ostatniego.źródło
DATA
i jak odbierasz wprowadzanie tekstu?<<\DATA\ntext input\nDATA\n
jest upieczony, ale jest to tylko tekst przekazanysed
przez powłokę w dokumencie tutaj . Działa to tak samo jaksed 'script' filename
lubprocess that writes to stdout | sed 'script'
. To pomaga?D
każdej zmodyfikowanej linii jest podwójna? (sed
D
ponieważ wD
przeciwnym razieD
usuwa z wyjścia to, co teraz widzisz podwójnie. Właśnie dokonałem edycji - i mogę ją rozwinąć wkrótce.D
powiedziałem.Cóż, mogę wymyślić kilka prostych sposobów, ale żaden z nich nie obejmuje
grep
(który i tak nie zastępuje) anised
.Perl
Aby wymienić każde wystąpienie
"line"\n<second>
zother characters
, użytkowania:Lub, aby traktować wiele następujących po sobie wystąpień
"line"\n<second>
jako jednego i zastąpić je wszystkie jednymother characters
, użyj:Przykład:
-00
Powoduje Perl odczytać pliku w trybie „ust”, co oznacza, że „linie” są zdefiniowane przez\n\n
zamiast\n
istocie każdy akapit jest traktowana jako linia. Podstawienie pasuje zatem do nowej linii.awk
Ten sam podstawowy pomysł, ustawiamy separator rekordów (
RS
), aby\n\n
zamazał cały plik, a następnie wyjściowy separator rekordów na nic (w przeciwnym razie drukowany jest dodatkowy znak nowej linii), a następnie używamysub()
funkcji, aby dokonać zamiany.źródło
awk
powinna byćprint;}' file
. Muszę unikać Perla i najlepiej go używaćsed
, w każdym razie zasugerowałeś dobre alternatywy.przeczytaj cały plik i dokonaj globalnej zamiany:
źródło
${cmds}
jest specyficzne dla GNU - większość innychsed
będzie wymagać\n
ewline lub-e
przerwy międzyp
i}
. Możesz całkowicie pominąć nawiasy klamrowe - i przenośnie - a nawet uniknąć wstawienia dodatkowego\n
znaku ewline w pierwszej linii, takiego jak:sed 'H;1h;$!d;x;s/"line"\n<second>/other characters /g'
sed -n '1{h;n};H; ${x; s/"line"\n<second>/other characters /g; p}'
- staje się to jednak niemożliwe do utrzymania.Oto wariant odpowiedzi Glenna, który zadziała, jeśli wystąpi wiele kolejnych wystąpień (działa
sed
tylko z GNU ):To
:x
tylko etykieta dla rozgałęzień. Zasadniczo działa to tak, że sprawdza wiersz po podstawieniu, a jeśli nadal jest zgodny"line"
, rozgałęzia się z powrotem do:x
etykiety (tobx
robi) i dodaje kolejną linię do bufora i rozpoczyna przetwarzanie.źródło
sed
który przenosi obsługę etykiet nie-POSIX wystarczająco daleko, aby zaakceptować spację jako ogranicznik deklaracji etykiety. Należy jednak pamiętać, że każda innased
zawiedzie tam - i zawiedzieN
. GNUsed
łamie wytyczne POSIX, aby wydrukować przestrzeń wzorcową przed wyjściemN
z ostatniego wiersza, ale POSIX wyjaśnia, że jeśliN
polecenie zostanie odczytane w ostatnim wierszu, nic nie powinno zostać wydrukowane.v
komendzie GNU, która się psuje,sed
ale w GNU w wersji 4 i nowszej nie ma żadnej opcji.sed -e :x -e '/"line"/{$!N' -e '};s/"line"\n<second>/other characters/;/"line"/bx'
.