Навпроти хвоста: всі лінії, крім останніх n рядків


36

Як я можу відкинути останні п рядків файлу за допомогою фільтра командного рядка unix?

Це було б якось навпаки tail: tailвідкидає перші n рядків, а решта проходить через інші, але я хочу, щоб команда передавала все, крім останніх n рядків.

На жаль, я не знайшов нічого подібного - теж headне допомагає. EDIT : Принаймні, в Solaris він не бере негативних аргументів.

Оновлення: Мене найбільше цікавить рішення, яке працює для великих файлів, тобто журналів, де ви можете ознайомитись з тим, що сталося за останні хвилини.


FYI при використанні заголовка: Розміщуючи "-" перед номером з опцією -n, він друкує всі рядки кожного файлу, але не останні N рядків, як показано нижче,
G Koe

Відповіді:


38

Якщо у вас є GNU head, ви можете використовувати

head -n -5 file.txt

для друку всіх, крім останніх 5 рядків file.txt.

Якщо head -nнегативних аргументів немає, спробуйте

head -n $(( $(wc -l file.txt | awk '{print $1}') - 5 )) file.txt

11
(і моліться, щоб file.txtбуло не менше шести рядків ...)
CVn

1
На жаль, ця версія, яка не є GNU, також не працює з потоками
Арман

1
@ MichaelKjörling Принаймні, на ubuntu, це не проблема. Якщо файли мають менше рядків, ніж зазначено в head, повертається порожній вихід без помилок.
Альфаа

Якщо я не помиляюсь, голова -n 5 надрукує перші 5 рядків, не всі, крім останніх 5 ...
pypmannetjies

8
head file.txt               # first 10 lines
tail file.txt               # last 10 lines
head -n 20 file.txt         # first 20 lines
tail -n 20 file.txt         # last 20 lines
head -20 file.txt           # first 20 lines
tail -20 file.txt           # last 20 lines
head -n -5 file.txt         # all lines except the 5 last
tail -n +5 file.txt         # all lines except the 4 first, starts at line 5

1
Що це додає, що не було відповідено у прийнятій відповіді? Також, як і у ваших інших відповідях, кілька рядків пояснень вашої відповіді значно покращили б її.
music2myear

1
дуже хороший підсумок
ruanhao

5

Ось простий спосіб видалити останній рядок, який працює на BSD тощо.

sed '$d' input.txt

Вираз звучить "в останньому рядку, видаліть його". Інші рядки будуть надруковані, оскільки це sedповедінка за замовчуванням.

Ви можете зв'язати їх між собою, щоб видалити кілька рядків

sed '$d' input.txt | sed '$d' | sed '$d'

Це, правда, трохи важко, але робить лише одне сканування файлу.

Ви також можете поглянути на це, щоб отримати додаткові відповіді: https://stackoverflow.com/questions/13380607/how-to-use-sed-to-remove-last-n-lines-of-a-file

Ось однолінійка, адаптована з одного з моїх улюблених там:

N=10
sed -n -e ':a' -e "1,$N!{P;N;D;};N;ba"

Мені було весело розшифровувати це, і я сподіваюся, що ви теж це зробите (: Він робить буферні Nлінії, коли він сканує, але в іншому випадку досить ефективний.


3

Мені цікаво, чому ви вважаєте, що headце не варіант:

~$ man head
...
-n, --lines=[-]K
        print the first K lines instead of the first 10; 
        with the leading `-', print all but the last K lines of each file

Це, здається, відповідає вашому призначенню, використовуючи, наприклад:

head -n -20 yourfile.txt

5
Зауважте, що це стосується лише GNU head. У BSD headнемає цієї опції, тому ця відповідь не працюватиме на Solaris або інших Unixes без ядер GNU. ОП спеціально позначила це і Unix та Unix-Utils.
slhck

2
@slhck Не кажучи вже про те, що ОП згадувало, що це стосується Solaris.
CVn

На жаль, хтось зняв мою згадку про Соляріс. Але я все-таки повинен був зазначити, що версія голови цього не підтримує.
Ганс-Петер Стрер

1
Вибачте всіх. Я не помічав Соляріса, і не знав про різні версії голови.
Андерс Р. Биструп

1
@hstoerr Solaris зараз у ваших тегах :)
slhck

0

Ще один спосіб зробити це, якщо tail -nнегативні аргументи не будуть - це

tac file.txt | tail -n +6 | tac

Це видалить останні 5 рядків


Спасибі! Це чудова ідея, яку ніхто поки не придумав. На жаль, це було б досить неефективно для користувальницької справи, я мав на увазі це питання: якщо це великий файл, він не тільки буде повністю прочитаний один чи кілька разів, як і з іншими рішеннями, але, ймовірно, також буде записаний у диск до тимчасових файлів tac, якщо він не входить у пам'ять.
Ганс-Пітер Штерр

@ Ганс-Пітер Дуже правда. Вирішив написати сценарій python3 для цього. Спробуйте це github.com/atw31337/donkey . Я рекомендую використовувати параметри виводу. Вони запускаються набагато швидше, ніж використання переспрямувань.
atw31337

Чудово написано! Однак він читає файл двічі, що насправді не потрібно, якщо ви буферуєте останні n рядків, і це проблема у великих файлах. Особисто мені це вже не потрібно, але у випадку, якщо вам цікаво вдосконалювати його та потребуватимуть інші люди ... Зрештою, у цьому питанні було кілька лайків та закладок.
Ганс-Пітер Стрерр

@ Ганс-Пітер. Розмір буфера буде залежати від кількості рядків, які потрібно видалити. Це може бути проблемою, якщо з файлу потрібно скинути дуже велику кількість рядків. Щоб уникнути проблем, пов’язаних із пам’яттю, я переписав сценарій для використання методу підрахунку рядків з високими n значеннями та методу буферизації з нижчими n значеннями; однак після тестування його на дуже великому файлі метод початкового підрахунку рядків все ще швидший. Здається, управління буфером накладних коштів переважає кількість ліній накладних… або я просто чогось пропускаю.
atw31337

Приємно, але для Mac OS X-варіанту не існує команди tac за замовчуванням. :( Цей вид перемагає справу використання.
ingyhere
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.