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


64

Eu tenho arquivo de texto. Tarefa - obtém a primeira e a ú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 (apenas 1 e 5).

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

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


No seu segundo exemplo, wc -lnada tem a ver com a saída da última linha de um arquivo.
David Richerby

Respostas:


115

Solução sed :

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

Ao ler stdinif, seria 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

Solução de cabeça e cauda :

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

Quando os dados são provenientes 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 canalizado 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}

11
Obrigado! É a melhor resposta, porque não posso, (head -n1 file;tail -n1 file)tenho comando e pipe muito grandes como último símbolo. Tão | sed '1p;$!d'mais curto.
dmgl

Desculpem o meu inglês, se você não me entende - o problema é meu - conte-me e preparo uma apresentação melhor para você.
dmgl

7
Será que head && tailrealmente funciona para você? seq 10 | (head -n1 && tail -n1)imprime 1apenas.
glenn jackman

11
@ DavidConrad, para elaborar o que o caos disse, -e 1b- na primeira linha, ramifique até o final do script sed, quando a "impressão" implícita acontece. Se a entrada tiver apenas uma linha, sed termina. Caso contrário, para todas as linhas, exceto a última, exclua. Na última linha, a "impressão" implícita acontece novamente.
glenn jackman

11
@mikeserv: ;-) verifique quando tiver uma chance. Em uma única linha, evita efetivamente dobrá-lo na saída, mas em um caso de trabalho de várias linhas, apenas preserva a última linha ... pelo menos no GNU sed4.2.2. Felicidades.
precisa saber é o seguinte

23

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


10
Observe que, se a entrada tiver apenas uma linha, será impressa duas vezes. Você pode preferir sed -e 1b -e '$!d'se não quiser isso.
Stéphane Chazelas

10

Uma maneira 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 arycom o primeiro campo (ou seja, com índice 0) sendo a primeira linha de filee seu último campo sendo a última linha de file. O retorno de chamada cb(opcional, se você quiser eliminar todas as linhas da matriz) desativa todas as linhas intermediárias para não sobrecarregar a memória. Como 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='()'

7

Com sedvocê, você pode deliminar linhas se NÃO for o 1primeiro e NÃO o último $.
Use !para NOT(negar) uma condição e a X{Y..}construção para combinar as condições X AND Y :

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

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

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

6

Usando Perl:

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

O item acima imprime o primeiro item na saída de seq 10via the if 1..1, enquanto o or eoftambém imprime o último item.


3
Você poderia explicar como isso funciona? Por favor, evite dar respostas únicas sem uma explicação do que elas fazem e como.
terdon

11
o que faz /etc abrte yum.repos.dtem que fazer esta pergunta?
drs

@drs Editei a resposta para evitar o uso de 'ls' como exemplo de entrada.
dólmen

11
@ dolmen: pode ser uma boa idéia terminar a edição suprimindo todas as referências a / etc. Eu acho que isso foi adicionado após a primeira edição, mas, mesmo assim, como está, a resposta não faz sentido. Apenas uma sugestão.
Cbhihe

4

Sem gato:

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

ou

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

8
No primeiro, a ordem das linhas não é garantida.
Stéphane Chazelas

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.