使用nohup调用函数

27

我正在尝试使用nohup调用一个函数,就像这样:

function1(){
    while true 
    do
        echo "function1"
        sleep 1
    done
}

nohup function1 & 
# ...... some other code

但也许该函数没有被 nohup 看到,我会收到这个错误:

nohup: failed to run command `function1' : No such file or dictionary

我不想为我的函数创建新的sh文件。 我该如何解决这个问题?


1
nohup 命令需要一个文件作为参数(错误信息已经明确说明了),而不是一个函数。但你可以这样做:修改上面的脚本,使其接受一个新的参数(例如“--nohup”),当传递这个参数时,只需调用 function1 并将 nohup function1 & 替换为 nohup $0 --nohup & 即可。 - Adam Siemion
你的意思是我必须在函数中使用 nohup 命令吗?我对使用 --nohup 选项来调用函数感到困惑! - sajad
可能是重复的问题 如何在bash脚本中包含nohup? - jww
6个回答

34

另一种解决方案:

function background {
    echo TEST
}
export -f background 

nohup bash -c background &

1
如果您要传递参数,请不要忘记在函数调用周围加上引号:nohup bash -c 'background "hello there"'&,如果您的函数是 echo "$1" - Hashbrown
export: -f: unknown option - IceTea

10

nohup 仅适用于命令,而不是脚本函数。

例如,包含 function1() 的脚本(比如 func.sh)应该这样调用该函数:

function1(){
    while true 
    do
        echo "function1"
        sleep 1
    done

}

function1

现在使用nohup在后台调用脚本func.sh:

nohup ./func.sh &

如果您需要在脚本内部禁用挂起信号,请使用shell内置命令trap。这个示例忽略了SIGHUP,但也可以用来忽略其他信号(例如SIGINT)。

trap "" HUP   # script will ignore HANGUP signal

有没有办法在函数上应用nohup?我更倾向于不使用多个sh文件。 - sajad
不好意思,你不能这样做。你可以把常用的函数放在一个脚本中,然后进行调用;这样可以减少脚本数量。 - suspectus
4
有一个名为“trap”的命令可以用于捕获信号-请参见我编辑过的答案。这可能适合您的需求。 - suspectus

8

我找到了一个可行的解决方案 - 在文件中定义函数 (例如 .functions),然后使用 nohup 运行该函数:

nohup bash -c "source .functions; function1" &

已在 Ubuntu 13.04 上测试通过。


1
即使在同一Shell脚本中将functions定义为函数,nohup bash -c 'source .functions"arg1"'&仍会返回bash:.functions:没有那个文件或目录 - IceTea

7

不要使用专为文件设计的nohup,你可以使用以下方法实现相同的结果:

(trap '' HUP INT
 while true
 do
   echo "function1"
   sleep 1
 done
) </dev/null 2>&1 1>nohup.out &

由于我通常从父脚本启动这些进程,而且如果父进程被中断,父脚本可能会做其他工作,因此我希望子进程忽略INT信号并继续运行。


我不知道这个技巧。你能解释一下它是如何工作的吗? - brujoand
2
本质上,trap 捕获 SIGHUP 和 SIGINT 信号并忽略它们,使我们能够创建一个隔离的子 shell 来运行我们的函数。更详细的解释在这里:https://gist.github.com/bluekezza/e511f3f4429939a0f9ecb6447099b3dc - James Carey

6

由于 nohup 必须提供文件名而不是函数作为解决方法,因此可以采取以下操作:

function1(){
    while true 
    do
        echo "function1"
        sleep 1
    done

}

echo "$@" | grep -q -- "--nohup" && function1 || nohup $0 "$@" --nohup & 

当使用当前参数调用此脚本时:
  • `echo "$@" | grep -q -- "--nohup" 会返回一个错误状态,因此
  • nohup $0 "$@" --nohup & 将被调用,这将传递当前参数和一个新参数--nohup来调用此脚本
当带有参数--nohup调用此脚本时:
  • `echo "$@" | grep -q -- "--nohup" 将返回零状态(成功),因此
  • function1 将被调用

3

是的!这是可能的,但需要一些技巧,并严格遵守bash > v2兼容性:

function1(){ local msg=${*:-function1}; echo msg=$msg; }
nohup -- sh -c "$(typeset -f function1); function1 MESSAGE" >nohup.log 2>&1 0</dev/null &

不要忘记,"typeset"在bash中已经过时,现在推荐使用"declare"(尽管我并不完全同意这个决定)。


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