Как прочитать первую и последнюю строку из вывода cat?


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

Возможно awk и более короткое решение существует ...


Во втором примере wc -lне имеет ничего общего с выводом последней строки файла.
Дэвид Ричерби

Ответы:


115

Решение проблемы :

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

При чтении из stdinif выглядело бы так (например 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
Гленн Джекман

1
@DavidConrad, чтобы уточнить, что сказал хаос, -e 1b- в первой строке перейти к концу сценария sed, после чего происходит неявное «печатание». Если ввод только одна строка, sed заканчивается. В противном случае для всех строк, кроме последней, удалите. В последней строке неявное «print» повторяется снова.
Гленн Джекман

1
@mikeserv: ;-) проверьте, когда у вас есть шанс. В одной строке он эффективно предотвращает удвоение его на выходе, но в случае работы с несколькими строками он просто сохраняет последнюю строку ... по крайней мере, в GNU sed4.2.2. Приветствия.
Cbhihe

23

sed -n '1p;$p' file.txt напечатает 1-ю и последнюю строку файла file.txt.


10
Обратите внимание, что если вход имеет только одну строку, он будет напечатан дважды. Вы можете предпочесть, sed -e 1b -e '$!d'если вы этого не хотите.
Стефан Шазелас

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 И Y :

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

или вы можете использовать диапазон - от 2nd до la $- и удалить все строки в этом диапазоне, кроме $строки:

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
Не могли бы вы объяснить, как это работает? Пожалуйста, избегайте давать такие однострочные ответы без объяснения того, что они делают и как.
Terdon

1
что делать /etc abrtи yum.repos.dнужно делать этот вопрос?
DRS

@drs Я отредактировал ответ, чтобы не использовать 'ls' в качестве примера ввода.
дольмен

1
@dolmen: может быть хорошей идеей закончить редактирование, подавив все ссылки на / etc. Я думаю, что такое было добавлено после первого редактирования, но, несмотря на это, ответ не имеет никакого смысла вообще. Просто предложение.
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.