Як отримати зворотну поведінку для "хвоста" та "голови"?


55

Чи є спосіб head/ tailотримати документ і отримати зворотний вихід; тому що ви не знаєте, скільки рядків у документі?

Тобто я просто хочу отримати все, крім перших 2 рядків, foo.txtщоб додати до іншого документа.

Відповіді:


57

Ви можете використовувати це, щоб зняти перші два рядки:

tail -n +3 foo.txt

і це зняти два останні рядки:

head -n -2 foo.txt

(якщо припустити, що файл закінчується \nостаннім)


Так само, як і для звичайного використання, tailі headці операції не є руйнівними. Використовуйте, >out.txtякщо ви хочете перенаправити вихід на новий файл:

tail -n +3 foo.txt >out.txt

У випадку out.txt, коли він вже є, він замінить цей файл. Використовуйте >>out.txtзамість того, >out.txtякщо ви хочете, щоб вихід був доданий out.txt.


3
re "head, коли файл закінчується на \n" .. Він працює для всіх від'ємних цілих чисел, окрім -n -0яких взагалі нічого не повертає , як -n 0і (використовуючи: head (GNU coreutils) 7.4) ... Однак, коли трейлінг \nприсутній, -n -0чи друкується як можна було очікувати від -, тобто він друкує весь файл ... Отже, він працює для всіх ненульових негативних значень .. але -0виходить з ладу, коли немає трейлінгу\n
Peter.O

@fred: Дивно справді ... (те саме з 8.12 тут).
Стефан Гіменез

Чи є ця операція руйнівною? Як я хочу, щоб вона скопіювала зворотний бік перших двох рядків документа в інший?
chrisjlee

@Chris: Ні, вони просто друкують результат на своєму "стандартному виході", який зазвичай підключається до терміналу. Я додав деякі подробиці про те, як перенаправити вихід на деякі файли.
Стефан Гіменез

7
head -n -2не сумісний з POSIX .
l0b0

9

Якщо вам потрібні всі, крім перших ліній N-1, зателефонуйте tailз кількістю ліній +N. (Число - це номер першого рядка, який ви хочете зберегти, починаючи з 1, тобто +1 означає початок у верхній частині, +2 означає пропуск одного рядка тощо).

tail -n +3 foo.txt >>other-document

Немає простого, портативного способу пропустити останні N рядків. GNU headдозволяє head -n +Nяк аналог tail -n +N. В іншому випадку, якщо у вас є tac(наприклад, GNU або Busybox), ви можете комбінувати його з хвостом:

tac | tail -n +3 | tac

Портативно, ви можете використовувати фільтр awk (неперевірений):

awk -vskip=2 '{
    lines[NR] = $0;
    if (NR > skip) print lines[NR-skip];
    delete lines[NR-skip];
}'

Якщо ви хочете вилучити останні кілька рядків з великого файлу, ви можете визначити зміщення байту шматка для усікання, а потім виконати усікання dd.

total=$(wc -c < /file/to/truncate)
chop=$(tail -n 42 /file/to/truncate | wc -c)
dd if=/dev/null of=/file/to/truncate seek=1 bs="$((total-chop))"

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


У деяких системах (наприклад, сучасний Linux) ви можете усікати (згортати) файл на місці на початку, але, як правило, лише на величину, кратну розміру блоку FS (тому не дуже корисно в цьому випадку).
Стефан Шазелас

3

З tailдовідкової сторінки (GNU tail, тобто):

-n, --lines=K
   output the last K lines, instead of the last 10; or use -n +K to
   output lines starting with the Kth

Таким чином, слід додавати всі, крім перших 2 рядків, somefile.txtдо anotherfile.txt:

tail --lines=+3 somefile.txt >> anotherfile.txt

3

Для видалення перших n рядків можна використовувати sed GNU. Наприклад, якщо n = 2

sed -n '1,2!p' input-file

!Середній «виключити цей інтервал». Як ви можете собі уявити, можна отримати більш складний результат, наприклад

sed -n '3,5p;7p'

що покаже рядок 3,4,5,7. Більшу силу отримує використання регулярних виразів замість адрес.

Обмеження полягає в тому, що номери рядків повинні бути відомі заздалегідь.


1
Чому б не просто sed 1,2d? Простіше, як правило, краще. Крім того, ніщо у ваших прикладах не є специфічним для GNU Sed; всі ваші команди використовують стандартні функції POSIX Sed .
Wildcard

1

Ви можете використовувати diffдля порівняння виводу head/ tailз вихідним файлом, а потім видалити те саме, завдяки чому отримується обернена.

diff --unchanged-group-format='' foo.txt <(head -2 foo.txt)

1

Хоча tail -n +4для виведення файлу, починаючи з 4-го рядка (усі, крім перших 3 рядків), є стандартним та портативним, його headаналог ( head -n -3всі, крім останніх 3 рядків) не є.

Портативно, ви зробите:

sed '$d' | sed '$d' | sed '$d'

Або:

sed -ne :1 -e '1,3{N;b1' -e '}' -e 'P;N;D'

(майте на увазі, що в деяких системах, де sedє простір шаблону обмеженого розміру, він не масштабується до великих значень n).

Або:

awk 'NR>3 {print l[NR%3]}; {l[NR%3]=$0}'

1
{   head -n2 >/dev/null
    cat  >> other_document
}   <infile

Якщо <infileце звичайний lseek()файл з можливістю використання, то так, будь-ласка, не соромтеся. Вищезазначене - повністю підтримувана конструкція POSIX.


0

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

tac -r thefile.txt | очолити thisfile.txt (замінює файли)


0

Сподіваюся, я чітко зрозумів вашу потребу.

У вас є кілька способів виконати запит:

tail -n$(expr $(cat /etc/passwd|wc -l) - 2) /etc/passwd

Де / etc / passwd - ваш файл

2-е рішення може бути корисним, якщо у вас є величезний файл:

my1stline=$(head -n1 /etc/passwd)
my2ndline=$(head -n2 /etc/passwd|grep -v "$my1stline")
cat /etc/passwd |grep -Ev "$my1stline|$my2ndline"

0

Рішення для BSD (macOS):

Видаліть перші 2 рядки:

tail -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

Видалити останні 2 рядки:

head -n $( echo "$(cat foo.txt | wc -l)-2" | bc )

... не дуже елегантно, але виконує роботу!

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