我真正想做的事情
保存命令的输出并检查其返回状态。
解决方案
经过一些谷歌搜索,我在StackOverflow以及AskUbuntu和Unix/Linux StackExchange上找到了基本相同的答案:
if output=$(command); then
echo "success: $output"
fi
问题
当用command info put
尝试这个解决方案时,即使实际命令失败,if子句也会被执行,但我无法解释为什么?
我试图手动检查返回值$?
,似乎var=
更改了返回值:
$ info put
info: No menu item 'put' in node '(dir)Top'
$ echo $?
1
$ command info put
info: No menu item 'put' in node '(dir)Top'
$ echo $?
1
$ var=$(command info put)
info: No menu item 'put' in node '(dir)Top'
$ echo $?
0
$ var=$(command info put); echo $?
info: No menu item 'put' in node '(dir)Top'
0
当`
那么,为什么这种通用解决方案在这种情况下不起作用呢?如何更改/调整解决方案以使其正常工作?
我的环境/系统
我在Windows 10上使用WSL2 Ubuntu 20.04.2 LTS:
$ tmux -V
tmux 3.0a
$ echo $SHELL
/bin/bash
$ /bin/bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
$ info --version
info (GNU texinfo) 6.7
在使用命令信息尝试此解决方案时,即使实际命令失败,也会执行if子句,但我无法解释为什么?
事实上,当输出不是终端并且出现错误时,info
会与0
一起退出。
// texinfo/info.c
if ((!isatty (fileno (stdout))) && (user_output_filename == NULL))
{
user_output_filename = xstrdup ("-");
...
}
...
// in called get_initial_file()
asprintf (error, _("No menu item '%s' in node '%s'"),
(*argv)[0], "(dir)Top");
...
if (user_output_filename)
{
if (error)
info_error ("%s", error);
...
exit (0); // exits with 0!
}
参考文献:https://github.com/debian-tex/texinfo/blob/master/info/info.c#L848,https://github.com/debian-tex/texinfo/blob/master/info/info.c#L277,https://github.com/debian-tex/texinfo/blob/master/info/info.c#L1066。
为什么在这种情况下通用解决方案不起作用?
因为当命令的输出被重定向到非终端时,命令的行为会发生变化。
如何更改/调整解决方案以使其正常工作?
您可以模拟tty-https://unix.stackexchange.com/questions/157458/make-program-in-a-pipe-think-it-has-tty,https://unix.stackexchange.com/questions/249723/how-to-trick-a-command-into-thinking-its-output-is-going-to-a-terminal。
您可以获取命令的stderr
,并检查它是否为空或是否与某个正则表达式匹配。
我想你也可以联系texinfo的开发人员,让他们知道这是一个bug,并制作一个补丁,所以它就像exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
。
我没有检查命令的退出状态,而是保存了输出,并简单地检查是否有任何输出可以用于进一步处理(在我的情况下,管道进入更少(:
my_less () {
output=$("$@")
if [[ ! -z "$output" ]]; then
printf '%s' "$output" | less
fi
}
即使有info
中的错误,我的函数现在也能工作,因为错误只影响命令的退出状态。它的错误消息按预期写入stderr
,所以我使用这种行为。