使用bash nohup命令执行两个命令

8

我在我的 bashrc 中有一个小函数,可以运行脚本并在完成时将输出发送到我的电子邮件。 代码如下:

run() {
    email=example@gmail.com
    last="${!#}"
    rest="${@:1:($#-1)}"

    (nohup $rest &> $last < /dev/null; mail -s "$rest" "$email" < "$last") &
}

这个函数的使用方法如下:
run ./script.sh arg1 arg2 output

看起来大部分时间都能工作,但有时邮件没有发送,尽管脚本已经完成。我怀疑是因为我关闭了服务器终端造成的。在这些情况下,由于 nohup 的存在,脚本仍在运行,但最终不会发送邮件。希望得到一些指导,以便使其正常工作。


rest="${@:1:($#-1)}" 这种写法不太好 -- 无法准确地表示参数向量,因此存在参数字符串分割不正确、通配符扩展等风险。你可以使用 rest=( "${@:1:($#-1)}" ),然后用 "${rest[@]}"(或者对于单个参数主题行版本,使用 "${rest[*]}"... 或者更准确地,使用 printf -v rest_cmd '%q ' "${rest[@]}",然后将 "$rest_cmd" 作为邮件参数)来扩展它。 - Charles Duffy
谢谢你的建议,我一定会改正的。 - skd
1个回答

11

有多种解决方法,但我认为我会推荐这个:

run() {
  email=example@gmail.com
  rest="${@:1:($#-1)}"

  nohup bash -c "$rest < /dev/null 2>&1 | mail -s \"$rest\" \"$email\"" &
}
问题在于您的nohup命令在/dev/null分号后结束,因此未应用于邮件部分。 (...)引入了一个子shell,但不是外部命令,因此nohup ( ... ) 不起作用,这就是为什么需要bash -c "..."(如果重要的话,也可以使用${SHELL} -c " ..."以增加可移植性)。当双引号被包含在另一组引号中时,需要对其进行转义。此外,临时文件不必要(除非您想出于某些原因将其保留下来-如果是这种情况,请随意重新添加重定向并使用;而不是|将命令分开)。不需要输出文件的情况下,您还可以放弃rest=...部分,并只调用run script.sh arg1 arg2,但如果您已经在其他代码中分散地调用它,则可能更简单将该部分留在其中-您必须自行解决该部分…

1
谢谢!我实际上尝试过nohup (...),但我对它不起作用感到非常困惑! - skd
输出文件对我很有用,所以我将您的脚本更改为nohup bash -c "$rest &> $last ; mail -s \"$rest\" \"$email\" < \"$last\"" &> /dev/null < /dev/null &< /dev/null的目的是避免nohup警告消息nohup: ignoring input。出于同样的目的,我在末尾添加了&> /dev/null - skd
解释很好,说明了为什么子Shell选项不起作用。 - ncoghlan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接