9

By referencing bash: silently kill background function process and Timeout a command in bash without unnecessary delay, I wrote my own script to set a timeout for a command, as well as silencing the kill message.

But I still am getting a "Terminated" message when my process gets killed. What's wrong with my code?

#!/bin/bash
silent_kill() {
    kill $1 2>/dev/null
    wait $1 2>/dev/null
}
timeout() {
    limit=$1 #timeout limit
    shift
    command=$* #command to run
    interval=1 #default interval between checks if the process is still alive
    delay=1 #default delay between SIGTERM and SIGKILL
    (
        ((t = limit))
        while ((t > 0)); do
            sleep $interval;
            #kill -0 $$ || exit 0
            ((t -= interval))
        done
        silent_kill $$
        #kill -s SIGTERM $$ && kill -0 $$ || exit 0 
        sleep $delay
        #kill -s SIGKILL $$
    ) &> /dev/null &
    exec $*
}
timeout 1 sleep 10
Community
  • 1
  • 1
ggaaooppeenngg
  • 1,323
  • 3
  • 17
  • 27
  • what's the question? – SMA Sep 13 '15 at 16:13
  • 1
    @SMA I don't want get 'Terminated' from terminal. – ggaaooppeenngg Sep 13 '15 at 16:15
  • I feel this might be a good time to step back and wonder what you'd be using this for. The "Terminated" message is useful information about the command you launched: it happened to end because of a signal rather than normal process completion. Your comments make it seem like you're not interested in that. If you're not interested in keeping the command invocation as transparent as possible to the parent shell, there's little point for you to use the `exec` wrapper; you'd be better off launching the command as a background task and monitoring it from the foreground script. – JB. Sep 14 '15 at 04:15
  • (Unless you need terminal I/O, but it seems strange to need timeout interruption on an interactive process.) – JB. Sep 14 '15 at 04:16

3 Answers3

6

There's nothing wrong with your code, that "Terminated" message doesn't come from your script but from the invoking shell (the one you launch your script from).

You can deactivate if by disabling job control:

$ set +m
$ bash <your timeout script>
JB.
  • 40,344
  • 12
  • 79
  • 106
  • Can I set it temporarily in the script, not in the interactive bash? – ggaaooppeenngg Sep 14 '15 at 03:29
  • I'm afraid you can't: the script doesn't know about the interactive shell, and doesn't have the ability to alter is settings. It only works the other way round: the script can inherit environment and settings from the shell. – JB. Sep 14 '15 at 04:04
  • Probably I'm missing something. I get rid of the _Termianted_ just adding [` &> /dev/null`](https://stackoverflow.com/a/2292885/4970442). – Pablo Bianchi Mar 12 '19 at 04:30
  • @PabloBianchi your invocation case is probably simpler than OP's here. Notice he *does* have the `&> /dev/null` – JB. Mar 12 '19 at 14:40
  • 1
    @JB. Also in my case it wasn't the ad-hoc function the one invoking the shell, but the [coreutils homonym command `timeout`](https://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html#timeout-invocation): `timeout duration command ... &> /dev/null`. – Pablo Bianchi Mar 12 '19 at 16:36
1

Perhaps bash has moved on in 4 years. I do know you can avoid getting Terminated by disowning a child process. You can no longer job control it though. Eg:

$ sleep 100 &
[1] 15436
$ disown -r
$ kill -9 15436

help disown:

disown [-h] [-ar] [jobspec ...]
Remove jobs from current shell.
Removes each JOBSPEC argument from the table of active jobs. Without any JOBSPECs, the shell uses its notion of the current job.

  • -a remove all jobs if JOBSPEC is not supplied
  • -h mark each JOBSPEC so that SIGHUP is not sent to the job if the shell receives a SIGHUP
  • -r remove only running jobs
Community
  • 1
  • 1
meuh
  • 11,500
  • 2
  • 29
  • 45
1

Internally the shell maintains a list of children it forked and wait()s for any of them to exit or be killed. When a child's exit status was collected, the shell prints a message. This is called monitoring in shell parlance.

It seems you want to turn off monitoring. Monitoring is managed with the m option; to turn it on, use set -m (the default at startup). To turn it off, set +m.

Note that monitoring off also disables messages for asynchronous jobs, e.g. no more messages like

$ sleep 5 &
[1] 59468
$
[1]  + done       sleep 5
$
Jens
  • 69,818
  • 15
  • 125
  • 179