重定向STDOUT和STDERR时遇到一个奇怪的问题。以下按预期工作:
$ gvim --version > /tmp/version.out
$ ls -l /tmp/version.out
-rw-r--r--. 1 blah blah 3419 Jun 27 17:28 /tmp/version.out
输出文件中有 3419 个字符,当我查看该文件时,它包含了我的期望。
但是,当我执行以下操作时,它无法正常工作:
$ gvim --version > /tmp/version.out 2> /tmp/version.err
$ ls -latr /tmp/version.*
-rw-r--r--. 1 blah blah 0 Jun 27 17:29 /tmp/version.out
-rw-r--r--. 1 blah blah 0 Jun 27 17:29 /tmp/version.err
请注意,.out和.err文件这次都是零长度。我用 ls 命令尝试了这个,它按预期工作:
$ ls . /ZZZ > /tmp/ls.out 2> /tmp/ls.err
$ ls -l /tmp/ls.*
-rw-r--r--. 1 blah blah 50 Jun 27 17:45 /tmp/ls.err
-rw-r--r--. 1 blah blah 33 Jun 27 17:45 /tmp/ls.out
这里,STDERR被正确地重定向:
$ cat /tmp/ls.err
ls: cannot access /ZZZ: No such file or directory
我对 gvim --version 进行了分析,并确认它正在尝试将版本信息写入STDOUT(fd 1)。无论哪种方式都没关系,因为我试图捕获STDOUT和STDERR。
这里发生了什么?
答案 0 :(得分:5)
恭喜,您刚刚在gvim
中发现了一个错误!
正确的程序是file a new issue on GitHub。
您应首先尝试该错误的其他变体,以便开发人员更轻松地进行调试。
例如,仅重定向STDERR也会导致错误,因为没有写入输出。还有返回成功(0),这显然是一个错误。
$ gvim --version 2> /tmp/version.err
$ echo $?
0
只需查看代码,就可以在version printing中的某个位置搜索错误,或者在泛型--version参数处理中的任何位置搜索not being done by gtk。
发生了什么事?
由gvim
的开发人员制作的程序错误,除非您有编码经验,否则我不建议您努力寻找其根本原因{{1或者如果你想学习,vim
如何运作。在这种情况下,您的最佳镜头是fork the repo,在修复后,提交拉取请求,以便每个人都可以从您的工作中受益。
答案 1 :(得分:1)
当标准错误不是终端时,触发错误的特定条件似乎是。当我尝试将标准错误重定向到另一个终端设备时,--version
消息仍然打印到标准输出。
ek@Io:~$ gvim --version 2>/dev/null
ek@Io:~$ tty
/dev/pts/1
ek@Io:~$ who
ek tty7 2017-07-05 02:48 (:0)
ek pts/1 2017-07-10 09:10 (192.168.10.3)
ek pts/3 2017-07-10 09:23 (192.168.10.3)
ek@Io:~$ gvim --version 2>/dev/pts/3
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Nov 24 2016 16:44:48)
....
显然Vim会调用isatty(2)
来帮助确定它是否应该使用终端。来自gui.c
的评论:
如果仍然启动并且没有地方输入文本,则返回TRUE。 对于GTK和X11,我们检查stderr是不是tty,这意味着我们(可能)是从桌面启动的。还要检查stdin,“vim>& file” 允许在stdin上输入。
但该评论的其余部分(即我没有强调的部分)以及多个文件中isatty(2)
的实例,使得不应立即明白应该更改的内容。
在源树上运行grep -RF 'isatty(2)'
显示此内容在gui.c
,message.c
和main.c
中使用。 (当然,不意味着该错误存在于所有这些文件中。)您也可以查看all the instances of isatty
in the source code。
无论如何,作为jirislav says,这应该被报告为一个错误 - 即使问题的完整解释尚不明显。我能够使用当前的上游源(commit 163095f)重现这一点。