Jaki jest najlepszy sposób na usunięcie segmentu z pliku tekstowego?


Odpowiedzi:


12

możesz spróbować:

cat textfile | head -n 45 | tail -n 26

lub

cat textfile | awk "20 <= NR && NR <= 45" 

aktualizacja:

Jak wskazał Mahomedalid, catnie jest to konieczne i trochę zbędne, ale zapewnia czyste, czytelne polecenie.

Jeśli ci catto przeszkadza, lepszym rozwiązaniem byłoby:

<textfile awk "20 <= NR && NR <= 45"

2
awk NR==20,NR==45 textfileteż działa i czyta z łatwością.
ephemient

Bardziej podoba mi się użycie stdin, ma on globalną spójność z resztą nix
Stefan

1
Czytanie z argumentów wiersza poleceń ma również spójność z innymi narzędziami UNIX, a moim głównym celem było zademonstrowanie ,operatora zasięgu awk .
ephemient

lol, miałem na myśli @adam. ale tak, podoba mi się twoja sugestia
Stefan,

Myślę, że odpowiedź @ ephemient jest tutaj najlepsza. W przeciwnym razie polecenia są raczej tajemnicze.
Léo Léopold Hertz 준영

13

Jeszcze prościej:

sed -n '20,45p;45q' < textfile

Flaga -n wyłącza domyślne wyjście. „20,45” dotyczy wierszy od 20 do 45 włącznie. Polecenie „p” drukuje bieżącą linię. I q kończy pracę po wydrukowaniu linii.


1
+1 ładne, lubię, ale jego linia od 20 do 45 :)
Stefan

1
ok ok, zredagowałem to, żeby powiedzieć 20,45 :-)
dkagedal

Usunięcie qpolecenia (wszystko, począwszy od ;) poprawiło dla mnie wydajność podczas wyodrębniania pojedynczej linii 26995107 z pliku 27169334 linii.
Ruslan

6

To nie jest odpowiedź, ale nie można jej opublikować jako komentarza.

Inny (bardzo szybki) sposób na to zasugerował Mikeserv tutaj :

{ head -n 19 >/dev/null; head -n 26; } <infile

Korzystając z tego samego pliku testowego co tutaj i tej samej procedury, oto kilka testów porównawczych (wyodrębnianie wierszy 1000020-1000045):

mikeserv :

{ head -n 1000019 >/dev/null; head -n 26; } <iplist

real    0m0.059s

Stefan :

head iplist -n 1000045 | tail -n 26

real    0m0.054s

Są to zdecydowanie najszybsze rozwiązania, a różnice są znikome (dla pojedynczego przejścia) (próbowałem z różnymi zakresami: kilka linii, miliony linii itp.).

Wykonanie tego bez rury może jednak stanowić znaczącą zaletę dla aplikacji, która musiała szukać w wielu zakresach linii w podobny sposób, na przykład:

for  pass in 0 1 2 3 4 5 6 7 8 9
do   printf "pass#$pass:\t"
     head -n99 >&3; head -n1
done <<1000LINES 3>/dev/null
$(seq 1000)
1000LINES

... które drukuje ...

pass#0: 100
pass#1: 200
pass#2: 300
pass#3: 400
pass#4: 500
pass#5: 600
pass#6: 700
pass#7: 800
pass#8: 900
pass#9: 1000

... i czyta plik tylko raz.


Inne rozwiązania sed/ awk/ perlodczytują cały plik, a ponieważ chodzi o duże pliki, nie są one zbyt wydajne. Wrzuciłem kilka alternatyw, które exitlub quit po ostatniej linii w określonym zakresie:

Stefan :

awk "1000020 <= NR && NR <= 1000045" iplist

real    0m2.448s

vs.

awk "NR >= 1000020;NR==1000045{exit}" iplist

real    0m0.243s

dkagedal ( sed):

sed -n 1000020,1000045p iplist

real    0m0.947s

vs.

sed '1,1000019d;1000045q' iplist

real    0m0.143s

Steven D :

perl -ne 'print if 1000020..1000045' iplist

real    0m2.041s

vs.

perl -ne 'print if $. >= 1000020; exit if $. >= 1000045;' iplist

real    0m0.369s

+1 Myślę, że to najlepsza odpowiedź tutaj! Byłoby miło dowiedzieć się, ile to zajmuje czasu awk NR==1000020,NR==1000045 textfilew twoim systemie.
Léo Léopold Hertz 준영

3
ruby -ne 'print if 20 .. 45' file

1
kolego rubyisto, dostaję mój głos, proszę pana
Stefan

1
Skoro już to robimy, dlaczego nie python -c 'import fileinput, sys; [sys.stdout.write(line) for nr, line in enumerate(fileinput.input()) if 19 <= nr <= 44]'? :-P Jest to coś, co Ruby, wzorowane na Perlu, zainspirowane przez awk / sed, może z łatwością zrobić.
ephemient

2

Ponieważ sed i awk zostały już zrobione, oto rozwiązanie perla:

perl -nle "print if ($. > 19 && $. < 46)" < textfile

Lub, jak wskazano w komentarzach:

perl -ne 'print if 20..45' textfile

2
O co chodzi z tymi wszystkimi dodatkowymi postaciami? Nie ma potrzeby usuwania i ponownego dodawania nowych linii, flip-flop zakłada porównanie z numerem linii, a operator rombu analizuje argumenty, jeśli są podane. perl -ne'print if 20..45' textfile
ephemient

1
Miły. -le jest trochę odruchu, jak sądzę, jeśli chodzi o resztę, nie mam wymówki oprócz ignorancji.
Steven D
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.