aboutsummaryrefslogtreecommitdiff
blob: 436fdc1e46b1f1ed68e0057aea350a42867fb5ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<?xml version="1.0" encoding="UTF-8"?>
<guide self="tools-reference/head-and-tail/">
<chapter>
<title><c>head</c> and <c>tail</c>  line extraction</title>
<body>

<p>
The <c>head</c> and <c>tail</c> utilities can be used to obtain only
the first or last parts of a file respectively. Both will read from
the files named on the commandline, or stdin if no files are provided.
</p>

<p>
The <c>head</c> utility takes a single argument, <c>-n</c>, which must
be followed by an integer indicating the desired number of lines to be
displayed.
</p>

<warning>
Use of the GNU <c>-c</c> option is unportable and should be avoided.
</warning>

<p>
For full details, see
<uri link="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/head.html">
IEEE Std 1003.1-2017-head</uri>. Note that <c>head(1)</c> on GNU systems
describes many non-portable options.
</p>

<p>
The <c>tail</c> utility is similar, but takes lines from the end of the
file. The <c>-n</c> argument specifies how many lines to display.
</p>

<p>
To specify "the last five lines", use <c>tail -n 5</c>. To specify "all
but the first five lines", use <c>tail -n +6</c>.
</p>

<codesample lang="ebuild">
# bad: drop first five lines, clumsily computing line count
tail -n $(($(wc -l in.txt | awk '{print $1}') - 5)) in.txt &gt; out.txt

# good: let tail count lines from the beginning of the file
tail -n +6 in.txt &gt; out.txt
</codesample>

<warning>
<c>head/tail -5</c> syntax is deprecated and not POSIX compliant.
</warning>

<p>
For full details, see
<uri link="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/tail.html">
IEEE Std 1003.1-2017-tail</uri>. Note that <c>tail(1)</c> on GNU systems
describes many non-portable options.
</p>
</body>

<section>
<title>Chaining <c>head</c> or <c>tail</c> with <c>sed</c></title>
<body>
<p>
Chaining <c>head</c> or <c>tail</c> with <c>sed</c> is usually
unnecessary. Use of addresses and early exit can do the same thing
with a single <c>sed</c> call:
</p>

<codesample lang="ebuild">
# bad: get the first five lines of input.txt with all 'foo'
# replaced with 'bar'
head -n 5 input.txt | sed -e 's/foo/bar/g' &gt; output.txt

# good: use sed's address ranges and command groups to do
# the same thing with only one fork
sed -n -e '1,5{ s/foo/bar/g ; p }' input.txt &gt; output.txt

# good: another way is with an extra command which exits
# on line 5
sed -n -e 's/foo/bar/gp ; 5q' input.txt &gt; output.txt

# bad: set foo to the first line containing somestring
foo=$(sed -n -e '/somestring/p' input.txt | head -n 1 )

# good: use early exit to do the same thing in pure sed
foo=$(sed -n -e '/somestring/{ p ; q }' input.txt )

# bad: output the last line matching 'somestring'
sed -n -e '/somestring/p' input.txt | tail -n 1

# good: do this in pure sed using the hold space
sed -n -e '/somestring/h ; $ {x;p}'
</codesample>

<p>
<c>tail -n X</c> where <c>X</c> is larger than one is possible to do
in pure <c>sed</c> but tricky. Using chained commands here is probably
simplest.
</p>

<p>
Finally, to extract a single specific line, use <c>sed</c> instead:
</p>

<codesample lang="ebuild">
sed -n -e '123p'
</codesample>

</body>
</section>
</chapter>
</guide>