Jak wydrukować wszystkie oprócz N-tego do ostatniego wiersza w sed?

9
  • Chciałbym zrobić uzupełnienie / „przeciwieństwo”

    sed 13q;d <file.txt
    

    Mówiąc bardziej ogólnie, czy możliwe jest wykonanie tego rodzaju uzupełnienia / odwrotności / odwrotności w sed? Czy tylko dla wyrażeń regularnych?

  • Jak wydrukować wszystkie oprócz trzeciego do ostatniego wiersza ?. Czy to wymaga dwóch taci liczy się do przodu sed? A może istnieje sposób sed, aby liczyć od tyłu?

izomorfizmy
źródło

Odpowiedzi:

12

Część 1

Po prostu dusuń 13. linię:

sed '13d' <file.txt

Ogólnym sposobem na uzupełnienie powyższych jest:

sed '13!d' <file.txt

Część 2

Ponieważ można to zrobić:

sed -n ':a;${P;q};N;4,$D;ba' <file.txt

Zwróć uwagę, że 4jest to jeden więcej niż wymagany numer. Więc jeśli chcesz ostatnią 10. linię, byłoby to 11.

Testowanie z seq:

$ seq 100 | sed -n ':a;${P;q};N;4,$D;ba'
98
$ 

Próba wyjaśnienia

:a        # define label a
${        # match the last line
    P     # print the first line of the pattern space
    q     # quit
}
N         # match all lines: append the next line to the pattern
4,${      # match the range of lines 4 to the end of the file
    D     # delete the first line of the pattern space
}
ba        # match all lines: jump back to label a 

Cenny dodatek Glenna Jackmana:

To był „tylko N-ty wiersz”. Oto „wszystko, ALE N-ta linia”:

sed -n ':a;${s/^[^\n]*\n//;p;q};N;4,${P;D};ba'

działa z GNU sed, \nsekwencja może nie działać z innymi seds.


Próbowałem tego z BSD sed (OSX) i okazało się, że nie działało to w powyższej formie. Problemy wydają się być następujące:

  1. ; używane do oddzielania linii wydaje się ogólnie działać, ale nie działa po etykiecie
  2. BSD sed wydaje się wymagać ;po ostatnim poleceniu w {}jednowierszowej grupie poleceń, podczas gdy GNU sed nie
  3. \nmożna na ogół stosować w wyrażeniu regularnym, ale najwyraźniej nie w []wyrażeniu nawiasowym. Aby wykluczyć [[:alnum:][:punct:][:graph:][:blank:]]znaki nowej linii, możemy użyć czegoś podobnego zamiast tego, chociaż może to wykluczać inne znaki (w szczególności inne znaki kontrolne).

Jest to więc próba wersji bardziej niezależnej od platformy:

sed -n ':a
${s/^[[:alnum:][:punct:][:graph:][:blank:]]*\n//p;q;};N;4,${P;D;};ba'

Wygląda na to, że działa pod OSX i Ubuntu.

Cyfrowa trauma
źródło
@jimmij Inne odpowiedzi dotyczące powiązanych pytań w sieci SE sugerują, że rozwiązanie head/ tailjest znacznie wolniejsze niż sedrozwiązanie. W każdym razie dzięki.
izomorfizmy
3
@ isomorphismes żaden program nie może rozpoznać liczby linii w pliku, chyba że przejdzie przez cały plik. Nie można tego obejść. Jedynym sposobem liczenia od dołu jest odwrócenie pliku i liczenie od góry lub dwukrotne parsowanie. Więc głowa / ogon będą tak szybko, jak to możliwe.
terdon
@ isomorphismes ... ponieważ ( head/ tail) są zoptymalizowane do robienia tego, co robią.
peterph
@ isomorphismes - edytowane ze wszystkimi potrzebnymi częściami
Digital Trauma
Miły! Musiałem zmienić odpowiedź, ponieważ spodziewałem się, że będzie to bardziej skomplikowane. :)
Peter