windowssedgnutac

sed and tac: write error: Invalid argument


I'm using GNU Coreutils on Windows. I want to get last error line from log file

The SED regex works fine (but finds first entry in file)

c:\path\sed -n "/70\-Error/{p;q}" MyFile.log

the TAC command

c:\path\tac MyFile.log

successfully reverses the whole file, without error

but when I combine the two I get the last match line from the file output, as expected, but also an error:

c:\path\tac MyFile.log | c:\path\sed -n "/70\-Error/{p;q}"

gives

14/02/2018 10:19:03 [9] 70-Error: Errorcode: Query returned error 524 (Query timeout)
c:\path\tac: write error: Invalid argument

EDIT:

sed -n "p" MyFile.log

gives output

sed -n "p" MyFile.log | cat

also gives output, with no error

sed -n "p" MyFile.log | sed -n "/70\-Error/{p;q}"

gives first matching line and error:

30/01/2018 10:30:28 [7] 70-Error: Action failed ....
sed: couldn't write 225 items to stdout: Broken pipe

Using CAT isntead of TAC:

cat MyFile.log | sed -n "/70\-Error/{p;q}"

gives first matching line then error - looks same as TAC scenario:

30/01/2018 10:30:28 [7] 70-Error: Action failed ...
cat: write error: Invalid argument

Other tests:

sed -n "/fe80::a828:2146:58d1:28df/{p}" MyFile.log

is fine but

sed -n "/fe80::a828:2146:58d1:28df/{p}" MyFile.log | tac

gives no output and only this error instead:

sed: couldn't flush stdout: Invalid argument

I thought the problem might be associated with the fact that MyFile.log had a full path, including spaces, and as such was quoted - so I copied MyFile.log to same folder as GNU tools so everything was in current folder and no complex filename ... but same thing.

sed -n "p" MyFile.log | tac

gives (first) 25 lines from file, in reverse order, then:

sed: couldn't write 225 items to stdout: Broken pipe

maybe some sort of memory / cache-size limitation?

sed --unbuffered

didn't change anything.

MyFile.log is 4MB and 27,000 lines

EDIT2:

tac MyFile.log | sed "/70\-Error/h;$!d;x"

works fine, even for quoted MyFile.log containing spaces


Solution

  • This might work for you (GNU sed):

    sed '/70\\-Error/h;$!d;x' file
    

    This copies an error message into the hold space and at the end of file prints it.

    N.B. Uses \\ to represent \ as a single backslash is a quoting metacharacter in sed.

    To print all the lines following the last error message use:

    sed '/70-Error/h;//!H;$!d;x' file
    

    To print a selective number of lines following the last error message, say 3, use:

    sed '/70-Error/h;//!H;$!d;x;s/\(\(\n[^\n]*\)\{3\}\).*/\1/' file
    

    Or, more easy on the eye:

    sed -r '/70-Error/h;//!H;$!d;x;s/((\n[^\n]*){3}).*/\1/' file