Chcę zastąpić tylko pierwsze k
wystąpienia słowa.
W jaki sposób mogę to zrobić?
Na przykład. Powiedz plik foo.txt
zawiera 100 wystąpień słowa „linux”.
Muszę wymienić tylko pierwsze 50 wystąpień.
text-processing
sed
awk
narendra-choudhary
źródło
źródło
Odpowiedzi:
Pierwsza sekcja poniżej opisuje użycie
sed
do zmiany pierwszych k-wystąpień na linii. Druga sekcja rozszerza to podejście, aby zmienić tylko pierwsze k-wystąpienia w pliku, niezależnie od tego, w której linii się pojawiają.Rozwiązanie zorientowane liniowo
W przypadku standardowego sed istnieje polecenie zastąpienia k-tego wystąpienia słowa w wierszu. Jeśli
k
wynosi 3, na przykład:Lub można zastąpić wszystkie wystąpienia:
Żadne z nich nie jest tym, czego chcesz.
GNU
sed
oferuje rozszerzenie, które zmieni k-te wystąpienie, a potem. Jeśli k wynosi 3, na przykład:Można je łączyć, aby robić, co chcesz. Aby zmienić pierwsze 3 wystąpienia:
gdzie
\n
jest to przydatne, ponieważ możemy być pewni, że nigdy nie występuje na linii.Wyjaśnienie:
Używamy trzech
sed
poleceń podstawienia:s/\<old\>/\n/g4
To rozszerzenie GNU zastąpić czwarty i wszystkie kolejne wystąpienia
old
z\n
.Rozszerzona funkcja wyrażenia regularnego
\<
służy do dopasowania początku słowa i\>
dopasowania do końca słowa. Zapewnia to, że dopasowywane są tylko pełne słowa. Rozszerzone wyrażenie regularne wymaga-E
opcjised
.s/\<old\>/new/g
Pozostały tylko trzy pierwsze wystąpienia,
old
co zastępuje je wszystkienew
.s/\n/old/g
Czwarte i wszystkie pozostałe wystąpienia
old
zostały zastąpione\n
w pierwszym kroku. To przywraca ich pierwotny stan.Rozwiązanie inne niż GNU
Jeśli GNU sed nie jest dostępny i chcesz zmienić pierwsze 3 wystąpienia
old
nanew
, użyj trzechs
poleceń:Działa to dobrze, gdy
k
jest mała, ale skaluje się słabo do dużejk
.Ponieważ niektóre sedy inne niż GNU nie obsługują łączenia poleceń ze średnikami, każde polecenie tutaj jest wprowadzane z własną
-e
opcją. Może być również konieczne sprawdzenie, czysed
obsługujesz symbole granic słów,\<
oraz\>
.Rozwiązanie zorientowane na pliki
Możemy nakazać sedowi odczytanie całego pliku, a następnie wykonanie podstawień. Na przykład, aby zastąpić pierwsze trzy wystąpienia
old
użycia sed w stylu BSD:Polecenia sed
H;1h;$!d;x
odczytują cały plik.Ponieważ powyższe nie używa żadnego rozszerzenia GNU, powinno działać na sedku BSD (OSX). Należy pamiętać, że takie podejście wymaga
sed
obsługi długich linii. GNUsed
powinno być w porządku. Osoby używające wersji innej niż GNUsed
powinny przetestować swoją zdolność do obsługi długich linii.W przypadku GNU sed możemy dalej wykorzystać
g
lewę opisaną powyżej, ale z\n
zastąpioną przez\x00
, aby zastąpić pierwsze trzy wystąpienia:To podejście dobrze się skaluje i
k
staje się duże. Zakłada się jednak, że\x00
nie ma go w oryginalnym ciągu. Ponieważ niemożliwe jest umieszczenie znaku\x00
w ciągu bash, jest to zazwyczaj bezpieczne założenie.źródło
tr '\n' '|' < input_file | sed …
. Ale, oczywiście, to przekształca cały sygnał wejściowy w jedną linię, a niektóre sedy inne niż GNU nie mogą obsługiwać dowolnie długich linii. (2) Mówisz: „… powyżej cytowany ciąg'|'
powinien zostać zastąpiony dowolnym znakiem lub ciągiem znaków,…” Ale nie możesz użyć,tr
aby zastąpić znak ciągiem (o długości> 1). (3) W swoim ostatnim przykładzie mówisz-e 's/\<old\>/new/' -e 's/\<old\>/w/' | tr '\000' '\n'\>/new
. Wydaje się, że to literówka-e 's/\<old\>/new/' -e 's/\<old\>/new/' -e 's/\<old\>/new/' | tr '\000' '\n'
.Korzystanie z Awk
Poleceń awk można użyć do zastąpienia pierwszych N wystąpień słowa zamiennikiem.
Polecenia zostaną zastąpione tylko wtedy, gdy słowo jest w pełni zgodne.
W poniższych przykładach, jestem zastępując pierwsze
27
wystąpieniaold
znew
Korzystanie z sub
Wymiana pola ręcznie
Przeprowadzanie kontroli wcześniej
WYNIKI
Na przykład
do
źródło
$i
trochę, został zredagowany, dzięki :)Powiedz, że chcesz zastąpić tylko trzy pierwsze wystąpienia ciągu ...
uwaga: powyższe prawdopodobnie nie będzie działać z osadzonymi komentarzami
... lub w moim przykładzie przypadku „1” ...
WYDAJNOŚĆ:
Tam używam dwóch znaczących technik. Przede wszystkim każde wystąpienie
1
na linii jest zastępowane przez\n1
. W ten sposób, wykonując następnie zamiany rekurencyjne, mogę być pewien, że nie zastąpię wystąpienia dwukrotnie, jeśli mój ciąg zastępujący zawiera mój ciąg zastępujący. Na przykład, jeśli mogę wymienićhe
zhey
nim będzie nadal działać.Robię to tak:
Po drugie, liczę zamienniki, dodając znak do
h
starego miejsca dla każdego wystąpienia. Gdy osiągnę trzy, nie będzie już więcej. Jeśli zastosujesz to do swoich danych i zmienisz\{3\}
całkowitą liczbę żądanych zamienników oraz/\n1/
adresy na cokolwiek, co chcesz zastąpić, powinieneś wymienić tylko tyle, ile chcesz.Zrobiłem wszystkie te
-e
rzeczy dla czytelności. POSIXly Można to napisać w ten sposób:I w / GNU
sed
:Pamiętaj też, że
sed
jest on zorientowany liniowo - nie czyta całego pliku, a następnie próbuje zapętlić go z powrotem, jak to często bywa w innych edytorach.sed
jest prosty i wydajny. To powiedziawszy, często wygodnie jest zrobić coś takiego:Oto mała funkcja powłoki, która łączy ją w prosto wykonane polecenie:
Dzięki temu mogę zrobić:
...i dostać...
...lub...
... żeby dostać ...
... lub, aby dopasować swój przykład (o mniejszym rzędzie wielkości) :
źródło
Krótka alternatywa w Perlu:
Zmień wartość „$ n $ na swoje upodobania.
Jak to działa:
new
przezold
(s/old/new/
) i gdy to możliwe, zwiększa ona zmienną$i
(++$i
).1 while ...
), o ile$n
w sumie dokonał mniej niż podstawień i może dokonać co najmniej jednego podstawienia w tym wierszu.źródło
Użyj pętli powłoki i
ex
!Tak, to trochę głupie.
;)
Uwaga: Może się to nie powieść, jeśli
old
w pliku jest mniej niż 50 wystąpień . (Nie przetestowałem tego.) Jeśli tak, plik pozostanie niezmodyfikowany.Jeszcze lepiej, użyj Vima.
Wyjaśnienie:
źródło
Prostym, ale niezbyt szybkim rozwiązaniem jest zapętlenie poleceń opisanych w /programming/148451/how-to-use-sed-to-replace-only-the-first-occurrence-in-a -plik
Ta konkretna komenda sed prawdopodobnie działa tylko dla GNU sed i jeśli newword nie jest częścią oldword . W przypadku wersji innych niż GNU zobacz tutaj, jak zastąpić tylko pierwszy wzorzec w pliku.
źródło
Za pomocą GNU
awk
możesz ustawić separator rekordówRS
na słowo, które ma być zastąpione ograniczeniem przez granice słów. Jest to przypadek ustawienia separatora rekordów na wyjściu na słowo zastępcze dla pierwszychk
rekordów, przy zachowaniu oryginalnego separatora rekordów dla resztyLUB
źródło