Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have text file. Task - get first and last line from file after

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

$ cat file
1
2
3
4
5

Need this without cat output (only 1 and 5).

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

Maybe awk and more shorter solution exist...

share|improve this question
    
In your second example, wc -l has nothing to do with outputting the last line of a file. –  David Richerby Jun 26 at 8:06

6 Answers 6

up vote 17 down vote accepted

sed Solution:

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

When reading from stdin if would look like this (for example 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 & tail Solution:

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

When data is comming from a command (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

And also the piped example with 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}
share|improve this answer
    
Thank you! It's the best answer because i cannot do (head -n1 file;tail -n1 file) i have very big command and pipe as last symbol. So | sed '1p;$!d' shorter one. –  blackbird- Jun 25 at 11:09
    
Note that if the input has only one line, it will be printed twice with both the sed and awk ones. The awk one will print an empty line for an empty input. –  Stéphane Chazelas Jun 25 at 11:11
    
Sorry for my English, if you don't understand me - it's my problem - tell me about it and i prepare better presentation for you. –  blackbird- Jun 25 at 11:12
    
@StéphaneChazelas Thank you for this Note! Demo: file with only 1. Command $ cat file | sed '1p;$!d' #return 1 1 and $ cat file | awk 'NR==1; END{print}' return 1 1 –  blackbird- Jun 25 at 11:18
1  
@DavidConrad, to elaborate on what chaos said, -e 1b -- on the first line, branch to the end of the sed script, at which point the implicit "print" happens. If the input is only one line long, sed ends. Otherwise, for all lines except the last, delete. On the last line, the implicit "print" happens again. –  glenn jackman Jun 26 at 19:10

Using Perl:

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

The above prints the first item in the output of ls /etc via the if 1..1, while the or eof will also print the last item. Hence the output above is showing the results from ls /etc, only printing these 2 items but omitting everything else.

share|improve this answer
3  
Could you explain how this works? Please avoid giving such one-liner answers without an explanation of what they do and how. –  terdon Jun 25 at 18:35
1  
what do /etc abrt and yum.repos.d have to do this question? –  drs Jun 25 at 18:48
    
@drs I edited the answer to avoid using 'ls' as sample input. –  dolmen Jun 26 at 8:58
$ seq 100 | { IFS= read -r first; echo "$first"; tail -1; }
1
100
share|improve this answer

A funny pure Bash≥4 way:

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

After this, you'll have an array ary with first field (i.e., with index 0) being the first line of file, and its last field being the last line of file. The callback cb (optional if you want to slurp all lines in the array) unsets all the intermediate lines so as to not clutter memory. As a free by-product, you'll also have the number of lines in the file (as the last index of the array+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='()'
share|improve this answer

Without cat:

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

or

$ (head -n1 file;tail -n1 file)
1
5
share|improve this answer
4  
In the first one, the order of the lines is not guaranteed. –  Stéphane Chazelas Jun 25 at 11:08

sed -n '1p;$p' file.txt will print 1st and last line of file.txt .

share|improve this answer
5  
Note that if the input has only one line, it will be printed twice. You may prefer sed -e 1b -e '$!d' if you don't want that. –  Stéphane Chazelas Jun 25 at 11:06

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.