#!/bin/bash # Run a command line with a hang timeout, which kills the child process if it # doesn't produce a new line of output for $1 seconds. # This script has to be a separate process (rather than just a shell function) # so killing it doesn't kill the parent process. source sources/utility_functions.sh if test $Argc -lt 1 { echo "Usage: timeout.sh SECONDS COMMANDS..." > !2 exit 1 } trap "killtree $Pid" EXIT global TIMEOUT := $1 shift shell { eval @Argv } | tee $[while read -t "$TIMEOUT" -n 32 i { true; }; sleep 1; kill -TERM $Pid !2 >/dev/null] (CommandList children: [ (C {(source)} {(sources/utility_functions.sh)}) (If arms: [ (if_arm cond: [(C {(Lit_Other "[")} {($ VSub_Pound "$#")} {(-lt)} {(1)} {(Lit_Other "]")})] action: [ (SimpleCommand words: [{(echo)} {(DQ ("Usage: timeout.sh SECONDS COMMANDS..."))}] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[44])] ) (C {(exit)} {(1)}) ] spids: [-1 35] ) ] spids: [-1 52] ) (C {(trap)} {(DQ ("killtree ") ($ VSub_Dollar "$$"))} {(EXIT)}) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:TIMEOUT) op: Equal rhs: {(DQ ($ VSub_Number "$1"))} spids: [64] ) ] spids: [64] ) (C {(shift)}) (Pipeline children: [ (Subshell child:(C {(eval)} {(DQ ($ VSub_At "$@"))}) spids:[7179]) (C {(tee)} { (CommandSubPart command_list: (CommandList children: [ (Sentence child: (While cond: [ (Sentence child: (C {(read)} {(-t)} {(DQ ($ VSub_Name "$TIMEOUT"))} {(-n)} {(32)} {(i)}) terminator: ) ] body: (DoGroup children: [(Sentence child:(C {(true)}) terminator:)] spids: [103 108] ) ) terminator: ) (Sentence child:(C {(sleep)} {(1)}) terminator:) (SimpleCommand words: [{(kill)} {(-TERM)} {($ VSub_Dollar "$$")}] redirects: [(Redir op_id:Redir_Great fd:2 arg_word:{(/dev/null)} spids:[122])] ) ] ) left_token: ("> spids: [85 125] ) } ) ] negated: False ) ] )