sed: удалить все, кроме последних X строк файла

sed: удалить все, кроме последних X строк файла

Это можно сделать и с помощью других инструментов, но мне интересно узнать, как удалить все строки файла, кроме последних X, с помощью sed.

решение1

По сути, вы эмулируете tail. В этом примере X = 20. Следующий пример удалит все строки, кроме последних 20:

sed -i -e :a -e '$q;N;21,$D;ba' filename

Объяснение:

  • -e :a создает метку с именем
  • Следующий -e:
    • $q — выход и печать шаблона, если это последняя строка
    • N - следующая строка
    • 21,$D - выполняет команду "D", если номер строки >= 21 (21,$ = 21-я строка до $, что является концом файла)
    • ba - переход к метке «a», которая является началом скрипта.

решение2

sedдовольно сложно, когда дело касается такой задачи, как эта. tail, grepили awkсделал бы это намного проще и должен использоваться вместо этого. Тем не менее, этоявляетсявозможный.

Следующее решение адаптировано изsed и многострочный поиск и замена.

sed -ni '
    # if the first line copy the pattern to the hold buffer
    1h
    # if not the first line then append the pattern to the hold buffer
    1!H
    # if the last line then ...
    ${
            # copy from the hold to the pattern buffer
            g
            # delete current line if it is followed by at least X more lines
            # replace X-1 with the proper value
            s/.*\n\(\(.*\n\)\{X-1\}\)/\1/
            # print
            p
    }
' filename

Без комментариев получается изящная однострочная запись. Если вы хотите удалить, например, все, кроме последних десяти строк, используйте это:

sed -ni '1h;1!H;${;g;s/.*\n\(\(.*\n\)\{9\}\)/\1/;p;}' filename

решение3

На основе сценария враздел 4.13 руководства sedВы можете сделать что-то вроде этого:

n=10

(( n > 1 )) && script='1h; 2,'$n'{H;g;}; $q; 1,'$((n-1))'d; N; D'
(( n > 1 )) || script='$!d'

sed -i "$script" infile

решение4

tac|sed|tac>&&(mv||cat>)

Оба следующих фрагмента команды фактически удалят все, кроме самогопоследний5линиииз ~/file1. Если вы хотите сохранитьпоследний10линии, вы можете заменить: |sed '1,5!d;'на |sed '1,10!d;',и так далее, как вы считаете нужным.

  1. tac ~/"file1" |sed '1,5!d;' |tac >"/tmp/file2" &&mv  "/tmp/file2"  ~/"file1"
  2. tac ~/"file1" |sed '1,5!d;' |tac >"/tmp/file2" &&cat "/tmp/file2" >~/"file1"

Связанный контент