Comment lire la première et la dernière ligne de la sortie du chat?

64

J'ai un fichier texte. Tâche - obtenir la première et la dernière ligne du fichier après

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

$ cat file
1
2
3
4
5

Besoin de cela sans sortie chat (seulement 1 et 5).

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

Peut-être que awk et une solution plus courte existent ...

dmgl
la source
Dans votre deuxième exemple, wc -ln'a rien à voir avec la sortie de la dernière ligne d'un fichier.
David Richerby le

Réponses:

115

solution sed :

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

Lors de la lecture de stdinif ressemblerait à ceci (par exemple 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

tête et queue Solution:

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

Quand les données proviennent d'une commande ( 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 Solution:

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

Et aussi l'exemple piped avec 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}
le chaos
la source
1
Je vous remercie! C'est la meilleure réponse parce que je ne peux pas, (head -n1 file;tail -n1 file)j'ai une très grosse commande et un dernier tuyau. Si | sed '1p;$!d'courte.
dmgl
Désolé pour mon anglais, si vous ne me comprenez pas - c'est mon problème - parlez-en et je vous préparerai une meilleure présentation.
dmgl
7
Ça head && tailmarche vraiment pour vous? seq 10 | (head -n1 && tail -n1)impressions 1seulement.
Glenn Jackman
1
@DavidConrad, pour expliquer ce que le chaos a dit, -e 1b- sur la première ligne, branchez-vous à la fin du script sed, moment auquel l'implicite "empreinte" se produit. Si l'entrée ne comporte qu'une seule ligne, sed se termine. Sinon, pour toutes les lignes sauf la dernière, supprimez. Sur la dernière ligne, l'imprimé "implicite" se reproduit.
Glenn Jackman
1
@mikeserv: ;-) Vérifiez quand vous en avez l'occasion. Sur une seule ligne, cela évite effectivement de le doubler en sortie, mais sur un cas de travail à plusieurs lignes, il ne fait que conserver la dernière ligne ... au moins sous GNU sed4.2.2. À votre santé.
Cbhihe
23

sed -n '1p;$p' file.txt imprimera la 1ère et la dernière ligne du fichier file.txt.

schaiba
la source
10
Notez que si l'entrée n'a qu'une ligne, elle sera imprimée deux fois. Vous préférerez peut-être sed -e 1b -e '$!d'si vous ne le souhaitez pas.
Stéphane Chazelas
10

Un pur pur Bash≥4 drôle:

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

Après cela, vous aurez un tableau aryavec le premier champ (c'est-à-dire, index 0) en première ligne fileet le dernier champ en dernière ligne file. Le rappel cb(facultatif si vous souhaitez masquer toutes les lignes du tableau) désactive toutes les lignes intermédiaires afin de ne pas encombrer la mémoire. En tant que sous-produit gratuit, vous aurez également le nombre de lignes du fichier (en tant que dernier index du tableau + 1).

Démo:

$ 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
la source
7

Avec sedvous, vous pouvez dsupprimer des lignes si PAS le 1premier et NON le dernier $.
Utilisez !pour NOT(annuler) une condition et la X{Y..}construction pour combiner des conditions X AND Y :

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

ou vous pouvez utiliser une plage allant de 2nd à la $t et supprimer toutes les lignes de cette plage sauf la $ligne la t:

cmd | sed '2,${$!d;}'
don_crissti
la source
6

Utiliser Perl:

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

L’impression ci-dessus imprime le premier élément de la sortie de seq 10via if 1..1, tandis que l’ or eofimprimera également le dernier élément.

perlygatekeeper
la source
3
Pourriez-vous expliquer comment cela fonctionne? Évitez de donner de telles réponses uniques sans une explication de ce qu’elles font et comment.
terdon
1
qu'est-ce que /etc abrtet yum.repos.ddoivent faire cette question?
drs
@ drs J'ai modifié la réponse pour éviter d'utiliser "ls" comme exemple d'entrée.
dolmen
1
@dolmen: cela pourrait être une bonne idée de finir l'édition en supprimant toute référence à / etc. Je suppose que tel a été ajouté après votre première édition, mais tout de même, la réponse n’a aucun sens. Juste une suggestion.
Cbhihe
4

Sans chat:

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

ou

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

la source
8
Dans le premier cas, l'ordre des lignes n'est pas garanti.
Stéphane Chazelas
4
$ seq 100 | { IFS= read -r first; echo "$first"; tail -1; }
1
100
Glenn Jackman
la source