I would like to print out the last line of a file which contains one or more integers. "Hippo 9991" in example below. I tried to achieve this with gsed -n -r '/[0-9]+/h;x;$p'
command, but this doesn't quite work:
$ cat testfile
dog
lion 34
elephant
tiger 7
hippo 9991
zebra
gepard
cat
$ cat testfile | gsed -n -r '/[0-9]+/h;x;$p'
gepard
$
Could somebody explain what exactly gsed -n -r '/[0-9]+/h;x;$p'
does? As I understand, it should remove the trailing new-line character from line and read the line into pattern space. Then if the line in pattern space contains one or more integers, the line is put into hold space by replacing the previous data in hold space. This cycle is repeated until the last line which will be printed. Obviously I do not understand this correctly. More than a correct answer I would like to understand the work-flow of sed.
You almost have it. Here is what your script does:
/[0-9]+/h # if line contains a number, save the line to hold space
x # swap content of pattern space and hold space
$p # when on the last line print pattern space
You save the line to hold space then swap it back to pattern space. The contents of pattern space and hold space can be illustrated like this:
Line Command Pattern Space Hold Space
~~~~ ~~~~~~~~~~~ ~~~~~~~~~~~~~ ~~~~~~~~~~
1 /[0-9]+/h dog
1 x dog
2 /[0-9]+/h lion 34 lion 34
2 x lion 34 lion 34
3 /[0-9]+/h elephant lion 34
3 x lion 34 elephant
4 /[0-9]+/h tiger 7 tiger 7
4 x tiger 7 tiger 7
.
.
.
$ /[0-9]+/h cat geopard
$ x geopard cat
$ p geopard cat
What you really want is to only swap contents when the last line of the input file is reached. You can do this by grouping the x
and p
commands:
gsed -n -r '/[0-9]+/h; $ {x;p}' testfile
Output:
hippo 9991
The corresponding pattern space and hold space sequence is now:
Line Command Pattern Space Hold Space
~~~~ ~~~~~~~~~~~ ~~~~~~~~~~~~~ ~~~~~~~~~~
1 /[0-9]+/h dog
2 /[0-9]+/h lion 34 lion 34
3 /[0-9]+/h elephant lion 34
4 /[0-9]+/h tiger 7 tiger 7
.
.
.
$ /[0-9]+/h cat hippo 9991
$ x hippo 9991 cat
$ p hippo 9991 cat
The following works for me:
sed -n -r '/[0-9]+/ {h;x}; ${x;p}'
You want to run both h
and x
only if the integer is present, in your example, x
is run every time. At the end, you don't want to print the last line, but the last stored line, so you have to exchange them once more.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With