I have become so used to do this:
someprogram >output.file
I do it whenever I want to save the output that a program generates to a file. I am also aware of the two variants of this IO redirection:
someprogram 2>output.of.stderr.file
(for stderr)someprogram &>output.stderr.and.stdout.file
(for both stdout+stderr combined)
Today I have run across a situation I have not thought possible. I use the following command xinput test 10
and as expected I have the following output:
user@hostname:~$ xinput test 10 key press 30 key release 30 key press 40 key release 40 key press 32 key release 32 key press 65 key release 65 key press 61 key release 61 key press 31 ^C user@hostname:~$
I expected that this output could as usual be saved to a file like using xinput test 10 > output.file
. But when contrairy to my expectation the file output.file remains empty. This is also true for xinput test 10 &> output.file
just to make sure I do not miss something on stdout or stderr.
I am really confused and hence ask here if the xinput
program might have a way to avoid its output to be redirected?
update
I have looked at the source. It seems the output is generated by this code (see snippet below). It appears to me the output would be generated by an ordinary printf
//in file test.c static void print_events(Display *dpy) { XEvent Event; while(1) { XNextEvent(dpy, &Event); // [... some other event types are omnited here ...] if ((Event.type == key_press_type) || (Event.type == key_release_type)) { int loop; XDeviceKeyEvent *key = (XDeviceKeyEvent *) &Event; printf("key %s %d ", (Event.type == key_release_type) ? "release" : "press ", key->keycode); for(loop=0; loopaxes_count; loop++) { printf("a[%d]=%d ", key->first_axis + loop, key->axis_data[loop]); } printf("\n"); } } }
I modified the source to this (see next snippet below), which allows me to have a copy of the output on stderr. This output I am able to redirect:
//in file test.c static void print_events(Display *dpy) { XEvent Event; while(1) { XNextEvent(dpy, &Event); // [... some other event types are omnited here ...] if ((Event.type == key_press_type) || (Event.type == key_release_type)) { int loop; XDeviceKeyEvent *key = (XDeviceKeyEvent *) &Event; printf("key %s %d ", (Event.type == key_release_type) ? "release" : "press ", key->keycode); fprintf(stderr,"key %s %d ", (Event.type == key_release_type) ? "release" : "press ", key->keycode); for(loop=0; loopaxes_count; loop++) { printf("a[%d]=%d ", key->first_axis + loop, key->axis_data[loop]); } printf("\n"); } } }
My idea at present is that maybe by doing the redirect the program looses its ability to monitor the key-press key-release events.
Best Answer
It's just that when stdout is not a terminal, output is buffered.
And when you press Ctrl-C, that buffer is lost as/if it has not been written yet.
You get the same behavior with anything using
stdio
. Try for instance:Enter a few non-empty lines and press Ctrl-C, and you'll see the file is empty.
On the other hand, type:
And type enough on the keyboard for the buffer to get full (at least 4k worth of ouput), and you'll see the size of file grow by chunks of 4k at a time.
With
grep
, you can type Ctrl-D forgrep
to exit gracefully after having flushed its buffer. Forxinput
, I don't think there's such an option.Note that by default
stderr
is not buffered which explains why you get a different behaviour withfprintf(stderr)
If, in
xinput.c
, you add asignal(SIGINT, exit)
, that is tellxinput
to exit gracefully when it receivesSIGINT
, you'll see thefile
is no longer empty (assuming it doesn't crash, as calling library functions from signal handlers isn't guaranteed safe: consider what could happen if the signal comes in while printf is writing to the buffer).If it's available, you could use the
stdbuf
command to alter thestdio
buffering behaviour:There are many questions on this site that cover disabling stdio type buffering where you'll find even more alternative solutions.