为什么这个 bash 命令的返回值会改变?



我真正想做的事情

保存命令的输出并检查其返回状态。

解决方案

经过一些谷歌搜索,我在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,所以我使用这种行为。

相关内容

  • 没有找到相关文章

最新更新