Bash 为什么我的输出是标准输出而不是文件?

Bash 为什么我的输出是标准输出而不是文件?,bash,Bash,我有这样一个脚本: #!/usr/bin/bash COMMAND='some_command >> some_log_file 2>&1' until $COMMAND; do echo "some_command crashed with exit code $?. Respawning.." >&2 sleep 1 done (我从FWIW获得了,直到…完成位,但做了一点更改。) 当运行some_命令时,问题是输出不会进入some

我有这样一个脚本:

#!/usr/bin/bash
COMMAND='some_command >> some_log_file 2>&1'
until $COMMAND; do
    echo "some_command crashed with exit code $?.  Respawning.." >&2
    sleep 1
done
(我从FWIW获得了
,直到…完成
位,但做了一点更改。)

当运行
some_命令时,问题是输出不会进入
some_log_文件
。相反,它转到shell的stdout,我从中运行这个包装器脚本。在变量
command
中保留整个命令(包括重定向)的同时,如何使输出转到
某个日志文件
?其思想是将此脚本用作更通用的包装器脚本,可以与其他程序一起使用。(
命令实际上是作为参数传递到脚本中的)。

一种方法是

#!/usr/bin/bash
COMMAND='some_command >> some_log_file 2>&1'
until bash -c "$COMMAND"; do
    echo "some_command crashed with exit code $?.  Respawning.." >&2
    sleep 1
done
您的方法的问题在于,它不会将变量作为bash代码计算,而只是作为一系列文本字符串计算。这就像在Java字符串中放入
“1+1”
不会导致在不调用Java解释器的情况下打印
2

String cmd="1+1";
System.out.println(cmd);  // Prints 1+1
System.out.println(1+1);  // Prints 2

您正在将一些日志文件2>&1作为参数传递给一些命令,而不是将其作为重定向。这是因为解析shell语法(例如重定向)发生在执行参数扩展之前(处理中的点,
$foo
被相关变量的内容替换)。这实际上是理想的行为——否则就不可能在shell中编写代码来处理不受信任的数据

不要以字符串形式存储代码。您可以按字面意思将其包括在内:

until some_command >> some_log_file 2>&1; do
    echo "some_command crashed with exit code $?.  Respawning.." >&2
    sleep 1
done
…或者您可以将其存储在函数中:

mycode() { some_command >> some_log_file 2>&1; }

until mycode; do
    echo "some_command crashed with exit code $?.  Respawning.." >&2
    sleep 1
done

不知道为什么会发生这种情况,但在我的bash4.4
COMMAND='some_COMMAND>>some_log_file 2>&1'
中,它不起作用。相反,如果我使用$()格式而不是反勾号,效果会很好。基本上:永远,永远不要把命令放在字符串变量中。@geogevasiliou,它不起作用有什么奇怪的吗?@charlesduff感谢您提供Bash常见问题50链接。优秀的资源!很好的尝试,但是现在
until
循环不起作用。即,当我终止进程时,它不会再次自动重新启动。我猜
bash
每次都返回0。@Eddified,bash返回它运行的最后一个命令的退出状态。在这种情况下,这是
某些_命令的退出状态。我一点也不喜欢这个答案(它所描述的实践在更有趣的情况下不起作用——例如,使用变量的参数——除非您以引入安全漏洞的方式修改它,或者通过环境传递这些变量),但它肯定不会破坏
的功能,直到
循环(也就是说,我怀疑您终止进程的方式实际上并没有导致非零退出状态,或者正在终止shell)。@CharlesDuffy,尽管如此,它仍然不起作用。在我的情况下,它确实破坏了功能,我不知道为什么。如果我回到我的原始代码(如问题中所示),然后自动重新启动再次起作用。下面是我如何终止它:
$kill
。我已经尝试了好几次,我知道我没有终止shell。@Eddified,具体是哪个pid?至少有三个—父shell,子shell以
bash-c
开始,然后是命令。命令的退出状态是that接收一个SIGTERM,它在该命令的控制下(如果它捕获信号,它可以实现它想要的任何类型的处理程序)--您知道您的
some_命令
实现的退出状态为非零吗?@Eddified,…顺便说一句,如果您使它成为
bash-c'exec some_命令>>some_日志文件2>&1'
,那么
exec
将意味着您的
some_命令
将继承启动它的
bash
解释器的PID,因此你应该避免不必要地扩展你的呼叫链。这仍然不会让启动一个额外的口译员成为一个好主意,但至少可以通过使用口译员来减少损失。