Chcę usunąć jeden lub więcej określonych numerów linii z pliku. Jak mam to zrobić za pomocą sed?
Chcę usunąć jeden lub więcej określonych numerów linii z pliku. Jak mam to zrobić za pomocą sed?
Odpowiedzi:
Jeśli chcesz usunąć wiersze od 5 do 10 i 12:
sed -e '5,10d;12d' file
Spowoduje to wydrukowanie wyników na ekranie. Jeśli chcesz zapisać wyniki w tym samym pliku:
sed -i.bak -e '5,10d;12d' file
Spowoduje to utworzenie kopii zapasowej pliku file.baki usunięcie podanych wierszy.
Uwaga: Numery linii zaczynają się od 1. Pierwszy wiersz pliku to 1, a nie 0.
sed -e '5,$d' file
sed -e '5d' file. Składnia jest następująca <address><command>; gdzie <address>może być pojedyncza linia 5lub zakres linii podobnych 5,10, a polecenie dusuwa daną linię lub linie. Adresami mogą być również wyrażenia regularne lub znak dolara $wskazujący ostatnią linię pliku.
Możesz usunąć konkretny pojedynczy wiersz z jego numerem przez
sed -i '33d' file
Spowoduje to usunięcie wiersza z numerem 33 i zapisanie zaktualizowanego pliku.
sed -i '0,/<TARGET>/{/<NEW_VALUE>/d;}' '<SOME_FILE_NAME>'. Dzięki!
i awk również
awk 'NR!~/^(5|10|25)$/' file
$ cat foo
1
2
3
4
5
$ sed -e '2d;4d' foo
1
3
5
$
Jest to bardzo często objaw antypatternu. Narzędzie, które utworzyło numery linii, może zostać zastąpione tym, które natychmiast usuwa linie. Na przykład;
grep -nh error logfile | cut -d: -f1 | deletelines logfile
(gdzie deletelinesjest narzędzie, którego wyobrażasz sobie potrzebujesz) jest takie samo jak
grep -v error logfile
Powiedziawszy to, jeśli jesteś w sytuacji, w której naprawdę musisz wykonać to zadanie, możesz wygenerować prosty sedskrypt z pliku numerów linii. Humorystycznie (ale być może nieco myląco) możesz to zrobić sed.
sed 's%$%d%' linenumbers
To akceptuje plik z numerami wierszy, po jednym w wierszu, i generuje na standardowym wyjściu te same numery wierszy z ddopisywanymi po każdym. To jest prawidłowy sedskrypt, który możemy zapisać do pliku lub (na niektórych platformach) potok do innej sedinstancji:
sed 's%$%d%' linenumbers | sed -f - logfile
Na niektórych platformach sed -fnie rozumie argumentu opcji -oznaczającego standardowe wejście, więc musisz przekierować skrypt do pliku tymczasowego i wyczyścić go, gdy skończysz, lub może zastąpić samotną kreskę /dev/stdinlub /proc/$pid/fd/1jeśli twój system operacyjny (lub powłokę) ) ma to.
Jak zawsze, możesz dodać -iprzed -fopcją sededycji pliku docelowego na miejscu, zamiast generować wynik na standardowym wyjściu. Na platformach * BSDish (w tym OSX) należy również podać jawny argument -i; powszechnym idiomem jest podawanie pustego argumentu; -i ''.
pzamiast d, wraz z opcją -n(nie będzie działać bez -ni !dnie będzie działać).
Chciałbym zaproponować uogólnienie za pomocą awk.
Gdy plik jest tworzony przez bloki o ustalonym rozmiarze, a linie do usunięcia są powtarzane dla każdego bloku, awk może działać poprawnie w taki sposób
awk '{nl=((NR-1)%2000)+1; if ( (nl<714) || ((nl>1025)&&(nl<1029)) ) print $0}'
OriginFile.dat > MyOutputCuttedFile.dat
W tym przykładzie rozmiar bloku wynosi 2000 i chcę wydrukować linie [1..713] i [1026..1029].
NR to zmienna używana przez awk do przechowywania bieżącego numeru linii.% podaje resztę (lub moduł) podziału dwóch liczb całkowitych;nl=((NR-1)%BLOCKSIZE)+1Tutaj piszemy w zmiennej nl numer linii w bieżącym bloku. (patrz poniżej)||i &&są operatorem logicznym OR i AND .print $0 pisze pełną linięWhy ((NR-1)%BLOCKSIZE)+1:
(NR-1) We need a shift of one because 1%3=1, 2%3=2, but 3%3=0.
+1 We add again 1 because we want to restore the desired order.
+-----+------+----------+------------+
| NR | NR%3 | (NR-1)%3 | (NR-1)%3+1 |
+-----+------+----------+------------+
| 1 | 1 | 0 | 1 |
| 2 | 2 | 1 | 2 |
| 3 | 0 | 2 | 3 |
| 4 | 1 | 0 | 1 |
+-----+------+----------+------------+