2012-03-31 10 views
31

Por qué sería este trabajoejecutar la función de tiempo de espera con

timeout 10s echo "foo bar" # foo bar 

pero esto no

function echoFooBar { 
    echo "foo bar" 
} 

echoFooBar # foo bar 

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

y sería ¿cómo puedo hacer que funcione?

+0

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

Respuesta

32

timeout es un comando, por lo que se está ejecutando en un subproceso de su shell bash. Por lo tanto, no tiene acceso a las funciones definidas en su shell actual.

El comando timeout que se proporciona se ejecuta como un subproceso de tiempo de espera - un proceso de Grand-Child de su shell.

Puede confundirse porque echo es un shell incorporado y un comando separado.

Lo que puede hacer es poner su función en su propio archivo de script, chmod para que sea ejecutable, luego ejecútelo con timeout.

Como alternativa, bifurque, ejecute su función en un subconjunto y, en el proceso original, supervise el progreso, eliminando el subproceso si tarda demasiado.

+0

gracias por su solución! Pero como quiero agregar tiempo de espera como una opción adicional para un script existente, sería bastante poco convencional tener un archivo propio solo para la funcionalidad de tiempo de espera. ¿Es esta la única solución? – speendo

+4

@speendo Considere que 'timeout' funciona matando procesos enviándoles señales, eso es algo que solo puede hacer con los procesos. Por lo tanto, lo que sea que ejecutes con tiempo de espera debe ser su propio proceso. –

+1

@speendo También tenga en cuenta que bash es (AFAIK) de subproceso único, entonces, ¿qué podría hacer la funcionalidad de tiempo de espera si el subproceso está ejecutando su función? –

3

si solo desea agregar el tiempo de espera como una opción adicional para todo el script existente, puede hacer que pruebe la opción de tiempo de espera, y luego hacer que lo llame de forma recursiva sin esa opción.

example.sh:

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

la ejecución de este script sin tiempo de espera:

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

ejecutarlo con un tiempo de espera de un solo minuto:

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

Hay una alternativa en línea también el lanzamiento de una subproceso de bash shell:

 

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

echoFooBar 
sleep 20 
EOT 
 
8

Puede crear una función que le permitirá hacer lo mismo que el tiempo de espera, sino también para otras funciones:

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

y podría funcionar de la siguiente manera:

run_cmd "echoFooBar" 10 

Nota: La solución procedía de una de mis preguntas: Elegant solution to implement timeout for bash commands and functions

+0

¿no debería la subshell interna también ser eliminada después de 'wait $ child'? no hace nada dañino (aparte de esperar), pero sigue contando, incluso si el hijo ha terminado – 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

Como Douglas Leeder dijo que necesita un proceso separado para el tiempo de espera para enviar una señal. Solución alternativa al exportar la función a subcapas y ejecutar subshell manualmente.

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

Exportar -f no funciona en sh, does in bash. – J0hnG4lt

Cuestiones relacionadas