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.bak
i 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 5
lub zakres linii podobnych 5,10
, a polecenie d
usuwa 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 deletelines
jest 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 sed
skrypt 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 d
dopisywanymi po każdym. To jest prawidłowy sed
skrypt, który możemy zapisać do pliku lub (na niektórych platformach) potok do innej sed
instancji:
sed 's%$%d%' linenumbers | sed -f - logfile
Na niektórych platformach sed -f
nie 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/stdin
lub /proc/$pid/fd/1
jeśli twój system operacyjny (lub powłokę) ) ma to.
Jak zawsze, możesz dodać -i
przed -f
opcją sed
edycji 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 ''
.
p
zamiast d
, wraz z opcją -n
(nie będzie działać bez -n
i !d
nie 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)+1
Tutaj 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 |
+-----+------+----------+------------+