Как мне распечатать все, кроме N-й до последней строки в sed?

9
  • Я хотел бы сделать дополнение / "противоположность"

    sed 13q;d <file.txt
    

    В более общем смысле, возможно ли сделать такого рода дополнение / обратное / противоположное в sed? Или только для регулярных выражений?

  • Как мне распечатать все, кроме третьей до последней строки? Требуется ли это два tacи рассчитывать вперед sed? Или есть способ заставить sedсебя считать со спины?

isomorphismes
источник

Ответы:

12

Часть 1

Просто dвыберите 13-ую строку:

sed '13d' <file.txt

И общий способ сделать дополнение вышеупомянутого:

sed '13!d' <file.txt

Часть 2

Потому что это можно сделать:

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

Обратите внимание, что 4это на один номер больше, чем вам нужно. Так что, если бы вы хотели последнюю 10-ю строчку, это было бы 11.

Тестирование с seq:

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

Попытка объяснения

: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 

Ценное дополнение Гленна Джекмана:

Это была «только N-я линия». Вот "все НО-я строка":

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

работает с GNU Sed, \nпоследовательность может не работать с другими SED.


Я попробовал это с помощью BSD sed (OSX) и обнаружил, что он не совсем работает в приведенной выше форме. Проблемы, как представляется:

  1. ; используется для разделения строк, как правило, работает, но не работает после метки
  2. BSD sed, кажется, требует ;после последней команды в однострочной {}группе команд, тогда как GNU sed не делает
  3. \nобычно может использоваться в регулярном выражении, но, очевидно, не в []выражении в скобках. Таким образом, чтобы исключить символы новой строки, мы можем использовать что-то вроде [[:alnum:][:punct:][:graph:][:blank:]]этого, хотя это может исключать другие символы (особенно другие управляющие символы).

Так что это попытка более независимой от платформы версии:

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

Похоже, это работает под OSX и Ubuntu.

Цифровая травма
источник
@jimmij Другие ответы о связанных вопросах в сети SE предполагают, что head/ tailрешение намного медленнее, чем sedрешение. Спасибо хоть.
изоморфизм
3
@isomorphismes ни одна программа не может знать количество строк в файле, если она не проходит через весь файл. Обойти это невозможно. Единственный способ подсчитать снизу - это либо повернуть вспять файл и посчитать сверху, либо проанализировать его дважды. Таким образом, голова / хвост будут очень быстрыми темпами.
Тердон
@isomorphismes ... потому что они ( head/ tail) оптимизированы для того, что они делают.
Петер
@isomorphismes - отредактировано со всеми необходимыми частями
Digital Trauma
Ницца! Мне пришлось изменить свой ответ, так как я ожидал, что он будет более сложным. :)
Петер