Friday, July 29, 2022

[SOLVED] Howto print lines from a range starting from N and stopping at an address relative to the end?

Issue

I'm trying to print lines € [N;$-M] where $ is the address of the last line :

So far, I tried this :

$ sed -n '71,-61 p' myLogFile
sed: -e expression #1, char 4: unexpected `,'

and that :

$ sed -n '71,$-61 p' myLogFile
sed: -e expression #1, char 5: unknown command: `-'

BTW: N and M are not shell variables.

EDIT0 : My bad, sed is a stream editor (I thank @jhnc for this recall) therefore it cannot tell the number of lines in advance. The $ referring to the address of the last line can only be used in text editors of the vi family.

So I have to use another tool to do this.


Solution

sed is designed to work on piped input. It doesn't know in advance how long the input will be. Until the final line has been read, sed does not know how many lines remain to be processed.

It is possible to implement the desired behaviour in sed if the input is buffered before printing. For example:

$ ntom(){
    n=$1
    m=$2
    file=$3

    sed -nE '
        '$n' {
            # initialise buffer (avoids leading newline)
            h
            d
        }
        '$n',$ {
            # append to buffer
            H
            $!d

            # print buffer after final line read
            # delete unneeded lines off end
            x            
            s/(\n[^\n]*){'$m'}$//p
        }
    ' "$file"
}

$ ntom 71 61 myLogFile

but it is probably simpler to use tail and head:

$ tail -n +71 myLogFile | head -n -61

Implementations of tail and head often use a (circular) buffer on piped input too. They can be more efficient if input is seekable.


Also, as ed expects seekable input, as long as the file is not too big, you could use your original syntax with it:

echo '71,$-61p' | ed -s myLogFile


Answered By - jhnc
Answer Checked By - Gilberto Lyons (WPSolving Admin)