1

I'm playing around with xinput to watch keyboard events. I'd like to transform the output with awk and pass it to tee, printing to stdout and writing to a file simultaneously.

I watch events on device 14, type a single Space, then type Ctrl+C to exit:

$ xinput test 14
key release 36
key press   65
 key release 65
key press   37
key press   54
^C

I can transform this with awk:

$ xinput test 14 | awk '{ print $NF }'
36
65
 65
37
54
^C

Or I can pipe it to tee:

$ xinput test 14 | tee a.log
key release 36
key press   65
 key release 65
key press   37
key press   54
^C

$ cat a.log
key release 36
key press   65
 key release 65
key press   37
key press   54

But I can't pipe the transformed output to tee:

$ xinput test 14 | awk '{ print $NF }' | tee b.log
^C

$ cat b.log

I think I understand what's going on, and can boil it down to a simpler example where I cat stdin to tr and pipe that to tee.

$ cat | tr a x | tee x.log

If I type A B Enter, then Ctrl+C, the pipeline aborts before printing to stdout or writing to x.log (though the file itself is created):

ab
^C

$ cat x.log

If I type Ctrl+D instead of Ctrl+C, an EOF character signals the end of input, and output gets printed to stdout and written to x.log:

ab
xb

$ cat x.log
xb

I've tried a couple different approaches, but so far no success.

$ { xinput test 14 | awk '{ print $NF }' ; } > >(tee x.log)

$ exec {fd}> >(tee x.log)
$ xinput test 14 | awk '{ print $NF }' >& ${fd}
$ exec {fd}>&-

$ exec > >(tee x.log)
$ xinput test 14 | awk '{ print $NF }'

Can this be done?

1 Answer 1

0

I found two solutions.

  1. Use stdbuf to run awk with no output buffering.

    xinput test 14 | stdbuf -o0 awk '{ print $NF }' | tee b.log

  2. Add system("") call within the awk script

    xinput test 14 | awk '{ print $NF; system("") }' | tee b.log

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .