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?

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.