Display only the penultimate (second last) row of a text
Solution 1
There are many ways to do that, but this is the fastest one I've found -- and is the cleanest in my opinion.
Assuming that the poem is written in a file named poem
, you can use:
tail -n 2 poem | head -n 1
tail -n 2 poem
will write the last 2 lines of the file poem
.
head -n 1
will write the first line of the output provided by the previous tail
command.
Solution 2
Use ed, man!
ed -s poems <<< $'$-1\n'
This tells ed to open the poems
file in script mode (-s
) (so that it doesn't print extra messages), then sends an addressing command in a here-string that says "go to the last line of the file ($
), minus 1", which prints that line.
Given an input poem file of:
A is for awk, which runs like a snail, and
B is for biff, which reads all your mail.
C is for cc, as hackers recall, while
D is for dd, the command that does all.
E is for emacs, which rebinds your keys, and
F is for fsck, which rebuilds your trees.
G is for grep, a clever detective, while
H is for halt, which may seem defective.
I is for indent, which rarely amuses, and
J is for join, which nobody uses.
K is for kill, which makes you the boss, while
L is for lex, which is missing from DOS.
M is for more, from which Less was begot, and
N is for nice, which it really is not.
O is for od, which prints out things nice, while
P is for passwd, which reads in strings twice.
Q is for quota, a Berkeley-type fable, and
R is for ranlib, for sorting ar sic table.
S is for spell, which attempts to belittle, while
T is for true, which does very little.
U is for uniq, which is used after Sort, and
V is for vi, which is hard to abort.
W is for whoami, which tells you your name, while
X is, well, X, of dubious fame.
Y is for yes, which makes an impression, and
Z is for zcat, which handles compression.
... the result output is:
Y is for yes, which makes an impression, and
Solution 3
You would do
sed '2q;d' <(tac infile)
tac
well print the infile
file in reverse order unlike cat
and pass it as input to sed
and that will delete everyline ( here only first line) except the second and then quit immediately.
or alternatively:
tail -n2 infile | sed '2d'
Or with sed
only
sed 'x;$!d' <infile
The sed
is reading one line at a time and with hold-space x
we are saving the current line processing and will print it !d
(don't delete) once sed read all lines (or it's in last line) and since sed only can have one hold-space, so when it's last line the hold-space contains second last line; this is same as:
sed -n 'x;$p' <infile
Solution 4
Assuming your poem is in the poem
text document:
< poem tail -n 2 | head -n 1
Solution 5
awk
This works with GNU awk (Linux) and BSD awk (Mac).
You might want to ignore blank lines. In that case, you could use awk 'NF' file.txt
, and then pipe the output through one of the other methods described on this page.
You could also do it all in one pass through awk:
awk 'NF { a=b ; b=$0 } END { print a }' file.txt
NF
Only process lines that contain data.NF
stands for the number of fields in the line; values greater than 0 are treated as "true".{ a=b ; b=$0 }
Store the current non-blank line asb
, and the previous non-blank line asa
.
END { print a }
After examining the entire file, print the final value ofa
(the penultimate non-blank line).
If you don't want to omit the blank lines, just remove the NF
:
awk '{ a=b ; b=$0 } END { print a }' file.txt
Related videos on Youtube
Elena
Updated on September 18, 2022Comments
-
Elena over 1 year
I have a poem with an unknown number of rows and I want to display only the penultimate one. What command should I use?
-
BlackJack about 6 yearsWhy the redirection when you give the filename as argument to
tail
? Also it is much more common to append the redirection that to write it in front of the command. This way it looks more cryptic than it needs to be. -
Stéphane Chazelas about 6 years@BlackJack, there are many advantages. The first of which is that it allows you to but the filename at the beginning of the pipeline (which IMO is very common and not cryptic and shows better the flow of data), it avoids running
tail
if the file can't be opened and works with arbitrary file names (tail -n 2 "$file"
would fail for$file
s that start with-
.tail -n 2 -- "$file"
would still fail for a file called-
) -
Kusalananda about 6 yearsWith GNU
ed
anded
on OpenBSD, it's actually enough to run theed
script-1
. I believe that the POSIX spec. fored
requires this to be an error though. -
BlackJack about 6 yearsI've seen this the very first time so IMO it's not common. ☺ The flow is IMO better shown by
tail -n 2 < poem
because the<
symbolises an arrow depicting the flow frompoem
intotail
. -
gogoud over 2 yearsThis will output a query '?' if the input is a single line, whereas the
tail|head
approach will output the single line (even though it is not the penultimate line). So IMO this is a better answer.