hum*_*ace 50 io-redirection xinput
我已经习惯了这样做:
someprogram >output.file
每当我想将程序生成的输出保存到文件时,我都会这样做。我也知道这个IO 重定向的两个变体:
someprogram 2>output.of.stderr.file
(对于标准错误)someprogram &>output.stderr.and.stdout.file
(对于 stdout+stderr 组合)今天我遇到了一个我认为不可能的情况。我使用以下命令xinput test 10
,正如预期的那样,我有以下输出:
用户@主机名:~$ xinput 测试 10 按键 30 密钥释放 30 按键 40 密钥释放 40 按键 32 密钥发布 32 按键 65 密钥发布 65 按键 61 密钥发布 61 按键 31 ^C 用户@主机名:~$
我希望这个输出可以像往常一样保存到一个文件中,比如使用xinput test 10 > output.file
. 但是当与我的期望相反时,文件 output.file 仍然是空的。这也是正确的,xinput test 10 &> output.file
只是为了确保我不会错过 stdout 或 stderr 上的某些内容。
我真的很困惑,因此在这里询问该xinput
程序是否有办法避免其输出被重定向?
我看过源码。似乎输出是由这段代码生成的(见下面的片段)。在我看来,输出将由普通的 printf 生成
//在文件test.c中 static void print_events(Display *dpy) { XEvent 事件; 而(1){ XNextEvent(dpy, &Event); // [... 其他一些事件类型在这里被综合...] if ((Event.type == key_press_type) || (Event.type == key_release_type)) { 整数循环; 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"); } } }
我将源修改为这个(见下面的下一个片段),这允许我在 stderr 上拥有输出的副本。这个输出我能够重定向:
//在文件test.c中 static void print_events(Display *dpy) { XEvent 事件; 而(1){ XNextEvent(dpy, &Event); // [... 其他一些事件类型在这里被综合...] if ((Event.type == key_press_type) || (Event.type == key_release_type)) { 整数循环; 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"); } } }
我目前的想法是,通过执行重定向,程序可能会失去监视按键释放事件的能力。
Sté*_*las 55
只是当 stdout 不是终端时,输出被缓冲。
当您按下 时Ctrl-C,该缓冲区将丢失,因为/如果它尚未写入。
使用stdio
. 尝试例如:
grep . > file
Run Code Online (Sandbox Code Playgroud)
输入几行非空行并按Ctrl-C,您将看到文件为空。
另一方面,键入:
xinput test 10 > file
Run Code Online (Sandbox Code Playgroud)
并在键盘上输入足够的内容以使缓冲区变满(至少 4k 的输出),您将看到文件的大小一次以 4k 的块增长。
使用grep
,您可以在刷新缓冲区后键入Ctrl-Dforgrep
以正常退出。对于xinput
,我认为没有这样的选择。
请注意,默认情况下stderr
没有缓冲,这解释了为什么您会得到不同的行为fprintf(stderr)
如果,在 中xinput.c
,您添加一个signal(SIGINT, exit)
,即xinput
在接收到时告诉它优雅退出SIGINT
,您将看到file
不再为空(假设它没有崩溃,因为从信号处理程序调用库函数不能保证安全:考虑什么如果在 printf 写入缓冲区时输入信号,则可能发生)。
如果可用,您可以使用该stdbuf
命令来更改stdio
缓冲行为:
stdbuf -oL xinput test 10 > file
Run Code Online (Sandbox Code Playgroud)
此站点上有许多问题涉及禁用stdio类型缓冲,您可以在其中找到更多替代解决方案。
jll*_*gre 23
命令可以直接写入以/dev/tty
防止发生常规重定向。
$ cat demo
#!/bin/ksh
LC_ALL=C TZ=Z date > /dev/tty
$ ./demo >demo.out 2>demo.err
Fri Dec 28 10:31:57 2012
$ ls -l demo*
-rwxr-xr-x 1 jlliagre jlliagre 41 2012-12-28 11:31 demo
-rw-r--r-- 1 jlliagre jlliagre 0 2012-12-28 11:31 demo.err
-rw-r--r-- 1 jlliagre jlliagre 0 2012-12-28 11:31 demo.out
Run Code Online (Sandbox Code Playgroud)
看起来xinput
拒绝输出到文件但不拒绝输出到终端。为了实现这一点,可能xinput
使用系统调用
int isatty(int fd)
Run Code Online (Sandbox Code Playgroud)
检查要打开的文件描述符是否指向终端。
不久前,我在一个名为dpic
. 在我查看源代码和一些调试之后,我删除了相关的行isatty
,一切都再次按预期工作。
但我同意你的看法,这种经历非常令人不安;)