执行带超时的shell函数

spe*_*ndo 57 bash shell timeout function

为什么会这样呢?

timeout 10s echo "foo bar" # foo bar
Run Code Online (Sandbox Code Playgroud)

但这不会

function echoFooBar {
  echo "foo bar"
}

echoFooBar # foo bar

timeout 10s echoFooBar # timeout: failed to run command `echoFooBar': No such file or directory
Run Code Online (Sandbox Code Playgroud)

我怎样才能让它发挥作用?

Dou*_*der 45

timeout是一个命令 - 所以它在你的bash shell的子进程中执行.因此,它无法访问当前shell中定义的函数.

timeout给出的命令作为超时的子进程执行 - shell的一个子进程.

您可能会感到困惑,因为echo它既是shell内置命令又是单独命令.

你可以做的是将你的函数放在它自己的脚本文件中,chmod它是可执行的,然后执行它timeout.

或者fork,在子shell中执行你的函数 - 在原始进程中,监视进度,如果花费太长时间就杀死子进程.

  • @speendo认为`timeout`是通过发送信号来杀死进程的 - 这是你只能对进程做的事情.因此,无论你使用超时运行什么,都需要它自己的进程. (5认同)
  • @speendo另请注意,bash(AFAIK)是单线程的,因此如果线程正在执行您的函数,超时功能怎么办? (2认同)

use*_*194 39

正如Douglas Leeder所说,你需要一个单独的超时过程来发信号.通过将函数导出到子壳并手动运行子shell来解决此问题.

export -f echoFooBar
timeout 10s bash -c echoFooBar
Run Code Online (Sandbox Code Playgroud)

  • 或者保存导出(如果它不必是函数):`timeout 5s sh -c 'echo "foo bar"'` (3认同)

Edu*_*lar 23

还有一个内联替代方案还可以启动bash shell的子进程:


timeout 10s bash <<EOT
function echoFooBar {
  echo foo
}

echoFooBar
sleep 20
EOT


Tia*_*opo 9

您可以创建一个函数,它允许您执行与超时相同的操作,但也可以用于其他功能:

function run_cmd { 
    cmd="$1"; timeout="$2";
    grep -qP '^\d+$' <<< $timeout || timeout=10

    ( 
        eval "$cmd" &
        child=$!
        trap -- "" SIGTERM 
        (       
                sleep $timeout
                kill $child 2> /dev/null 
        ) &     
        wait $child
    )
}
Run Code Online (Sandbox Code Playgroud)

可以运行如下:

run_cmd "echoFooBar" 10
Run Code Online (Sandbox Code Playgroud)

注意:解决方案来自我的一个问题: 为bash命令和函数实现超时的优雅解决方案


Sup*_*ole 7

如果您只想为整个现有脚本添加超时作为附加选项,您可以让它测试超时选项,然后让它在没有该选项的情况下递归调用它。

例子.sh:

#!/bin/bash
if [ "$1" == "-t" ]; then
  timeout 1m $0 $2
else
  #the original script
  echo $1
  sleep 2m
  echo YAWN...
fi
Run Code Online (Sandbox Code Playgroud)

无超时运行此脚本:

$./example.sh -other_option # -other_option
                            # YAWN...
Run Code Online (Sandbox Code Playgroud)

以一分钟的超时运行它:

$./example.sh -t -other_option # -other_option
Run Code Online (Sandbox Code Playgroud)


小智 5

function foo(){
    for i in {1..100};
    do 
        echo $i;  
        sleep 1;
    done;
}

cat <( foo ) # Will work 
timeout 3 cat <( foo ) # Will Work 
timeout 3 cat <( foo ) | sort # Wont work, As sort will fail 
cat <( timeout 3 cat <( foo ) ) | sort -r # Will Work 
Run Code Online (Sandbox Code Playgroud)