2012-03-31 45 views
31

Tại sao công việc nàythực hiện chức năng với thời gian chờ

timeout 10s echo "foo bar" # foo bar 

nhưng điều này sẽ không

function echoFooBar { 
    echo "foo bar" 
} 

echoFooBar # foo bar 

timeout 10s echoFooBar # timeout: failed to run command `echoFooBar': No such file or directory 

và làm thế nào tôi có thể làm cho nó hoạt động?

+0

http://stackoverflow.com/questions/12321469/retry-a-bash-command-with-timeout/35977896#35977896 –

Trả lời

32

timeout là một lệnh - vì vậy nó đang thực hiện trong một tiến trình con của bash shell của bạn. Do đó nó không có quyền truy cập vào các hàm của bạn được định nghĩa trong trình bao hiện tại của bạn.

Lệnh timeout được đưa ra được thực thi dưới dạng tiến trình con của thời gian chờ - một quá trình con của bạn.

Bạn có thể bị nhầm lẫn vì echo là cả trình tích hợp vỏ và lệnh riêng biệt.

Những gì bạn có thể làm là đặt hàm của bạn vào tệp tập lệnh riêng của nó, chmod nó có thể thực thi, sau đó thực thi nó với timeout.

Ngoài ra ngã ba, thực hiện chức năng của bạn trong một vỏ phụ - và trong quá trình ban đầu, theo dõi tiến trình, giết chết tiến trình con nếu quá lâu.

+0

cảm ơn bạn cho giải pháp của bạn! Nhưng vì tôi muốn thêm thời gian chờ làm tùy chọn bổ sung cho tập lệnh hiện có, sẽ khá bất tiện khi có tệp riêng chỉ dành cho chức năng hết thời gian chờ. Đây có phải là giải pháp duy nhất không? – speendo

+4

@speendo Hãy xem xét rằng 'timeout' hoạt động bằng cách giết chết các quá trình bằng cách gửi tín hiệu cho chúng - đó là điều bạn chỉ có thể thực hiện với các quy trình. Vì vậy bất cứ điều gì bạn chạy với thời gian chờ cần phải là quá trình riêng của nó. –

+1

@speendo Cũng lưu ý rằng bash là (AFAIK) đơn luồng, vì vậy những gì có thể làm các chức năng timeout nếu thread đang thực hiện chức năng của bạn? –

3

nếu bạn chỉ muốn thêm thời gian chờ làm tùy chọn bổ sung cho toàn bộ tập lệnh hiện tại, bạn có thể làm cho nó kiểm tra tùy chọn thời gian chờ và sau đó gọi nó là tự động đệ quy mà không có tùy chọn đó.

example.sh:

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

chạy script này mà không có thời gian chờ:

$./example.sh -other_option # -other_option 
          # YAWN... 

chạy nó với một thời gian chờ một phút:

$./example.sh -t -other_option # -other_option 
16

Có một sự thay thế inline cũng tung ra một subprocess của bash shell:

 

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

echoFooBar 
sleep 20 
EOT 
 
8

Bạn có thể tạo một chức năng mà sẽ cho phép bạn làm tương tự như thời gian chờ mà còn cho các chức năng khác:

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 
    ) 
} 

Và có thể chạy như sau:

run_cmd "echoFooBar" 10 

Lưu ý: Các giải pháp đến từ một trong các câu hỏi của tôi: Elegant solution to implement timeout for bash commands and functions

+0

không nên là vỏ bọc bên trong nhất cũng bị giết sau khi 'chờ $ child'? nó không làm bất cứ điều gì gây hại (ngoài việc chờ đợi), nhưng nó vẫn tiếp tục đếm, ngay cả khi đứa trẻ đã hoàn thành – Blauhirn

2
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 
19

Như Douglas Leeder nói rằng bạn cần một quá trình riêng biệt cho thời gian chờ để báo hiệu. Giải pháp thay thế bằng cách xuất hàm thành subshells và chạy subshell theo cách thủ công.

export -f echoFooBar 
timeout 10s bash -c echoFooBar 
+0

Xuất -f không hoạt động trong sh, không trong bash. – J0hnG4lt

Các vấn đề liên quan