¿Cómo leer la primera y última línea de la salida de cat?


64

Tengo un archivo de texto Tarea: obtenga la primera y última línea del archivo después

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

$ cat file
1
2
3
4
5

Necesita esto sin salida de gato (solo 1 y 5).

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

Quizás exista una solución awk y más corta ...


En su segundo ejemplo, wc -lno tiene nada que ver con la salida de la última línea de un archivo.
David Richerby

Respuestas:


115

Solución sed :

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

Al leer de stdinif se vería así (por ejemplo 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

Solución de cabeza y cola :

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

Cuando los datos provienen de un 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

Solución awk :

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

Y también el ejemplo canalizado con 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
¡Gracias! Es la mejor respuesta porque no puedo hacerlo, (head -n1 file;tail -n1 file)tengo un comando muy grande y una tubería como último símbolo. Tan | sed '1p;$!d'corto.
dmgl

Perdón por mi inglés, si no me entiendes, es mi problema, cuéntamelo y te prepararé una mejor presentación.
dmgl

77
¿ head && tailRealmente funciona para ti? solo seq 10 | (head -n1 && tail -n1)impresiones 1.
Glenn Jackman

1
@DavidConrad, para elaborar sobre lo que dijo el caos, -e 1b- en la primera línea, bifurca hasta el final de la secuencia de comandos sed, en cuyo punto ocurre la "impresión" implícita. Si la entrada tiene solo una línea de longitud, sed termina. De lo contrario, para todas las líneas excepto la última, elimine. En la última línea, la "impresión" implícita ocurre nuevamente.
Glenn Jackman

1
@mikeserv: ;-) verifíquelo cuando tenga la oportunidad. En una sola línea, efectivamente evita duplicarlo en la salida, pero en un caso de trabajo de varias líneas, solo conserva la última línea ... al menos en GNU sed4.2.2. Salud.
Cbhihe

23

sed -n '1p;$p' file.txt imprimirá la primera y última línea de file.txt.


10
Tenga en cuenta que si la entrada tiene solo una línea, se imprimirá dos veces. Puedes preferir sed -e 1b -e '$!d'si no quieres eso.
Stéphane Chazelas

10

Una divertida forma pura de Bash≥4:

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

Después de esto, tendrá una matriz arycon el primer campo (es decir, con índice 0) como la primera línea de file, y su último campo será la última línea de file. La devolución de llamada cb(opcional si desea sorber todas las líneas de la matriz) desactiva todas las líneas intermedias para no saturar la memoria. Como subproducto gratuito, también tendrá el número de líneas en el archivo (como el último índice de la matriz + 1).

Manifestación:

$ 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

Con sedusted podría delegir líneas si NO es la 1primera Y NO la última $.
Use !para NOT(negar) una condición y la X{Y..}construcción para combinar condiciones X AND Y :

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

o puede usar un rango, de 2nd a la $t, y eliminar todas las líneas de ese rango, excepto la $línea t:

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

6

Usando Perl:

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

Lo anterior imprime el primer elemento en la salida de seq 10via the if 1..1, mientras or eofque también imprime el último elemento.


3
¿Podría explicar cómo funciona esto? Evite dar tales respuestas sin una explicación de lo que hacen y cómo.
terdon

1
¿Qué hago /etc abrty yum.repos.dtengo que hacer esta pregunta?
drs

@drs Edité la respuesta para evitar usar 'ls' como entrada de muestra.
dolmen

1
@dolmen: puede ser una buena idea terminar la edición suprimiendo toda referencia a / etc. Supongo que se agregó después de su primera edición, pero, de todos modos, tal como está la respuesta no tiene ningún sentido. Sólo una sugerencia.
Cbhihe

4

Sin gato:

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

o

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

8
En el primero, el orden de las líneas no está garantizado.
Stéphane Chazelas

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.