Як читати перший та останній рядок із виведення котів?


64

У мене є текстовий файл. Завдання - отримати перший та останній рядок із файлу після

$ cat file | grep -E "1|2|3|4" | commandtoprint

$ cat file
1
2
3
4
5

Потрібно це без виведення котів (лише 1 і 5).

~$ cat file | tee >(head -n 1) >(wc -l)
1
2
3
4
5
5
1

Можливо, існують якісніші та коротші рішення ...


У вашому другому прикладі wc -lнемає нічого спільного з виведенням останнього рядка файлу.
Девід Річербі,

Відповіді:


115

sed Рішення:

sed -e 1b -e '$!d' file

Коли читаєте, stdinчи виглядатиме це так (наприклад ps -ef):

ps -ef | sed -e 1b -e '$!d'
UID        PID  PPID  C STIME TTY          TIME CMD
root      1931  1837  0 20:05 pts/0    00:00:00 sed -e 1b -e $!d

голова та хвіст Рішення:

(head -n1 && tail -n1) <file

Коли дані надходять із команди ( ps -ef):

ps -ef 2>&1 | (head -n1 && tail -n1)
UID        PID  PPID  C STIME TTY          TIME CMD
root      2068  1837  0 20:13 pts/0    00:00:00 -bash

awk Рішення:

awk 'NR==1; END{print}' file

А також трубовий приклад із ps -ef:

ps -ef | awk 'NR==1; END{print}'
UID        PID  PPID  C STIME TTY          TIME CMD
root      1935  1837  0 20:07 pts/0    00:00:00 awk NR==1; END{print}

1
Дякую! Це найкраща відповідь, тому що я не можу зробити, (head -n1 file;tail -n1 file)я маю дуже велику команду і передачу, як останній символ. Так | sed '1p;$!d'коротше.
dmgl

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

7
Чи head && tailсправді працює для вас? тільки seq 10 | (head -n1 && tail -n1)відбитки 1.
glenn jackman

1
@DavidConrad, щоб детальніше розповісти про те, що сказав хаос, -e 1b- на першому рядку відгалужуйте до кінця сценарію sed, і в цей момент відбувається неявна «друк». Якщо вхід довгий лише один рядок, sed закінчується. В іншому випадку для всіх рядків, крім останнього, видаліть. В останньому рядку неявна "друк" повторюється.
glenn jackman

1
@mikeserv: ;-) перевіри це, коли ти маєш можливість. У одному рядку це ефективно запобігає подвоєнню його на виході, але у випадку з декількома лініями він просто зберігає останній рядок ... принаймні, у GNU sed4.2.2. Ура.
Cbhihe

23

sed -n '1p;$p' file.txt надрукує перший та останній рядок file.txt.


10
Зауважте, що якщо на вході є лише один рядок, він буде надрукований двічі. Ви можете віддати перевагу, sed -e 1b -e '$!d'якщо цього не хочете.
Stéphane Chazelas

10

Кумедний чистий Bash≥4 спосіб:

cb() { (($1-1>0)) && unset "ary[$1-1]"; }
mapfile -t -C cb -c 1 ary < file

Після цього у вас з'явиться масив , у якому перший рядок ary(тобто з індексом 0) є першим рядком file, а його останнє поле - останнім рядком file. Зворотний виклик cb(необов'язково, якщо ви хочете перервати всі рядки в масиві) знімає всі проміжні лінії, щоб не захаращувати пам'ять. Як безкоштовний побічний продукт, ви також матимете кількість рядків у файлі (як останній індекс масиву + 1).

Демонстрація:

$ mapfile -t -C cb -c 1 ary < <(printf '%s\n' {a..z})
$ declare -p ary
declare -a ary='([0]="a" [25]="z")'
$ # With only one line
$ mapfile -t -C cb -c 1 ary < <(printf '%s\n' "only one line")
$ declare -p ary
declare -a ary='([0]="only one line")'
$ # With an empty file
$ mapfile -t -C cb -c 1 ary < <(:)
declare -a ary='()'

7

З sedможна dдаліть лінії , якщо НЕ1 вул одна І НЕ Ла $т один.
Використовуйте !для NOT(заперечення) умови та X{Y..}конструкції для комбінування X AND Y умов:

cmd | sed '1!{$!d;}'

або ви можете використовувати діапазон - від 2nd до la $t - і видалити всі рядки в цьому діапазоні, крім $рядка la t:

cmd | sed '2,${$!d;}'

6

Використання Perl:

$ seq 10 |  perl -ne 'print if 1..1 or eof'
1
10

Наведене вище друкує перший елемент у висновку seq 10через через if 1..1, а or eofтакож друкує останній елемент.


3
Чи можете ви пояснити, як це працює? Будь ласка, уникайте давати такі відповіді з одного лайнера без пояснення того, що вони роблять і як.
тердон

1
що робити /etc abrtі yum.repos.dповинні робити це питання?
пр.

@drs Я відредагував відповідь, щоб уникнути використання "ls" як введення зразка.
долмен

1
@dolmen: може бути хорошою ідеєю закінчити редагування, придушивши всі посилання на / і т.д. Я думаю, що таке було додано після першого редагування yr, але, все одно, наскільки це відповідь, немає сенсу взагалі. Просто пропозиція.
Cbhihe

4

Без кота:

$ cat file |tee >(head -n1) >(tail -n1) >/dev/null
1
5

або

$ (head -n1 file;tail -n1 file)
1
5

8
У першому порядок ліній не гарантується.
Стефан Шазелас

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