Como ler a primeira e última linha da saída do gato?

56

Eu tenho um arquivo de texto. Tarefa - obter a primeira e última linha do arquivo após

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

$ cat file
1
2
3
4
5

Precisa disso sem saída de gato (somente 1 e 5).

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

Talvez haja uma solução awk e mais curta ...

    
por dmgl 25.06.2014 / 12:38

7 respostas

93

sed Solução:

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

Ao ler de stdin se ficaria assim (por exemplo 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 & cauda Solução:

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

Quando os dados vêm de um comando ( 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
Solução

awk :

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

E também o exemplo enviado com 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}
    
por 25.06.2014 / 13:00
19

sed -n '1p;$p' file.txt imprimirá a primeira e última linha do arquivo.txt.

    
por 25.06.2014 / 12:54
8

Uma forma engraçada de Bash ≥ 4:

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

Depois disso, você terá uma matriz ary com o primeiro campo (ou seja, com o índice 0 ) sendo a primeira linha de file e seu último campo sendo a última linha de file . O retorno de chamada cb (opcional se você quiser sugar todas as linhas da matriz) remove todas as linhas intermediárias para não sobrecarregar a memória. Como um subproduto gratuito, você também terá o número de linhas no arquivo (como o último índice da matriz + 1).

Demo:

$ 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='()'
    
por 25.06.2014 / 13:15
5

Usando o Perl:

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

O item acima imprime o primeiro item na saída de ls /etc via if 1..1 , enquanto o or eof também imprime o último item. Assim, a saída acima está mostrando os resultados de ls /etc , imprimindo apenas esses dois itens, mas omitindo todo o resto.

    
por 25.06.2014 / 20:26
4

Sem gato:

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

ou

$ (head -n1 file;tail -n1 file)
1
5
    
por 25.06.2014 / 12:55
4
$ seq 100 | { IFS= read -r first; echo "$first"; tail -1; }
1
100
    
por 25.06.2014 / 21:02
4

Com sed você poderia d elete linhas se NÃO o 1 st um E NÃO o la $ t um.
Use ! a NOT (negate) uma condição e a construção X{Y..} para combinar X AND Y condições:

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

ou você pode usar um intervalo - de 2 nd a la $ t - e excluir todas as linhas desse intervalo, exceto a linha $ t:

cmd | sed '2,${$!d}'
    
por 29.05.2015 / 19:02