¿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 ...

dmgl
fuente
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}
caos
fuente
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.

schaiba
fuente
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='()'
gniourf_gniourf
fuente
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;}'
don_crissti
fuente
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.

perlygatekeeper
fuente
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

fuente
8
En el primero, el orden de las líneas no está garantizado.
Stéphane Chazelas
4
$ seq 100 | { IFS= read -r first; echo "$first"; tail -1; }
1
100
Glenn Jackman
fuente