Как вывести все строки кроме последней

Идея для этой статьи у меня появилась, когда я увидел в одном из блогов, что данную задачу предлагается решать следующим однострочным кодом на языке Perl:

 echo -e '1\n2\n3' | perl -nalE 'push(@lines, $_); }{ say $lines[$_] foreach 0..$#lines -1'
А как же утилита head спросите Вы меня? Да, это лучший вариант. Но как оказалось, в некоторых системах нельзя использовать эту утилиту с отрицательным значением для параметра n (в случае когда неизвестно сколько строк в файле). О чем в исходной статье и было сказано, перед тем как предложить такой вариант решения.

Но, как мне кажется, в этом фрагменте кода есть две проблемы:

  1. Делается два прохода по данным. Первый, когда мы сохраняем каждую строку в массив @lines. И второй, когда выводим нужные строки
  2. Файл целиком хранится в памяти
Поэтому я решил предложить своё решение, у которого нет таких проблем:
 echo -e '1\n2\n3' | perl -nale 'push(@l, $_); print shift(@l) if @l> 1;'
Код совсем простой, но давайте его рассмотрим подробнее. Во-первых, мы не храним весь файл в памяти, а только то количество строк, которое мы не хотим выводить - своего рода буфер. Во-вторых, мы сразу принимаем решение о том выводить нам строку или нет. Количество строк, которое мы не выводим с конца задается числом. В данном примере это одна строка.

Замеры на потребляемую память я тестировал на файле размером 72M

 ls -lah big.file
 -rw-r--r-- 1 madskill madskill 72M ноя  1 03:56 big.file
Для первого варианта, получил следующие значения
 PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 23400 madskill  20   0  205844 188952   3960 S   0,0  4,8   0:07.44 perl
А для моего варианта следующие
 PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 23413 madskill  20   0   21056   3492   3248 S   0,0  0,1   0:10.71 perl
Из приведенных выше замеров видно, что мой вариант более экономично использует память. Но на этом я не остановился и далее грубо сравнил оба варинта по производительности. Получилось, что разницы почти нет. При повторных запусках был быстрее то один, то другой вариант. А разница между ними была очень маленькой.
 time cat big.file | perl -nalE 'push(@lines, $_); }{ say $lines[$_] foreach 0..$#lines -1;'> /dev/null
 real	0m1,789s
 user	0m1,662s
 sys	0m0,188s
 time cat big.file | perl -nale 'push(@l, $_); print shift(@l) if @l> 1;'> /dev/null
 real	0m1,732s
 user	0m1,688s
 sys	0m0,116s