Why can't I kill a timeout called from a Bash script with a keystroke?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












9















[Edit: This looks similar to some other questions asking how to kill all spawned processes – the answers all seem to be to use pkill. So the core of my question may be: Is there a way to propagate Ctrl-C/Z to all processes spawned by a script?]



When calling a SoX rec with the timeout command from coreutils (discussed here), there doesn't seem to be any way to kill it with a keystroke once it's been invoked from within a Bash script.



Examples:



timeout 10 rec test.wav


...can be killed with Ctrl+C or Ctrl+Z from bash, but not when it's been called from inside a script.



timeout 10 ping nowhere


...can be killed with Ctrl+C or Ctrl+Z from bash, and with Ctrl+Z when it's run from inside a script.



I can find the process ID and kill it that way, but why can't I use a standard break keystroke? And is there any way to structure my script so that I can?










share|improve this question



















  • 2





    Ctrl+Z does not kill processes, only pauses them. They will keep running if you give the bg of fg commands. Anyway, is there a difference between your 1st and 3d examples?

    – terdon
    Dec 5 '12 at 20:24











  • I don't have timeout on my system but killing sleep works whether it's typed directly on the command line, sourced, executed, or passed through the interpreter explicitly

    – Kevin
    Dec 5 '12 at 21:18











  • @terdon Thanks, I've clarified the examples.

    – meetar
    Dec 8 '12 at 17:28















9















[Edit: This looks similar to some other questions asking how to kill all spawned processes – the answers all seem to be to use pkill. So the core of my question may be: Is there a way to propagate Ctrl-C/Z to all processes spawned by a script?]



When calling a SoX rec with the timeout command from coreutils (discussed here), there doesn't seem to be any way to kill it with a keystroke once it's been invoked from within a Bash script.



Examples:



timeout 10 rec test.wav


...can be killed with Ctrl+C or Ctrl+Z from bash, but not when it's been called from inside a script.



timeout 10 ping nowhere


...can be killed with Ctrl+C or Ctrl+Z from bash, and with Ctrl+Z when it's run from inside a script.



I can find the process ID and kill it that way, but why can't I use a standard break keystroke? And is there any way to structure my script so that I can?










share|improve this question



















  • 2





    Ctrl+Z does not kill processes, only pauses them. They will keep running if you give the bg of fg commands. Anyway, is there a difference between your 1st and 3d examples?

    – terdon
    Dec 5 '12 at 20:24











  • I don't have timeout on my system but killing sleep works whether it's typed directly on the command line, sourced, executed, or passed through the interpreter explicitly

    – Kevin
    Dec 5 '12 at 21:18











  • @terdon Thanks, I've clarified the examples.

    – meetar
    Dec 8 '12 at 17:28













9












9








9


7






[Edit: This looks similar to some other questions asking how to kill all spawned processes – the answers all seem to be to use pkill. So the core of my question may be: Is there a way to propagate Ctrl-C/Z to all processes spawned by a script?]



When calling a SoX rec with the timeout command from coreutils (discussed here), there doesn't seem to be any way to kill it with a keystroke once it's been invoked from within a Bash script.



Examples:



timeout 10 rec test.wav


...can be killed with Ctrl+C or Ctrl+Z from bash, but not when it's been called from inside a script.



timeout 10 ping nowhere


...can be killed with Ctrl+C or Ctrl+Z from bash, and with Ctrl+Z when it's run from inside a script.



I can find the process ID and kill it that way, but why can't I use a standard break keystroke? And is there any way to structure my script so that I can?










share|improve this question
















[Edit: This looks similar to some other questions asking how to kill all spawned processes – the answers all seem to be to use pkill. So the core of my question may be: Is there a way to propagate Ctrl-C/Z to all processes spawned by a script?]



When calling a SoX rec with the timeout command from coreutils (discussed here), there doesn't seem to be any way to kill it with a keystroke once it's been invoked from within a Bash script.



Examples:



timeout 10 rec test.wav


...can be killed with Ctrl+C or Ctrl+Z from bash, but not when it's been called from inside a script.



timeout 10 ping nowhere


...can be killed with Ctrl+C or Ctrl+Z from bash, and with Ctrl+Z when it's run from inside a script.



I can find the process ID and kill it that way, but why can't I use a standard break keystroke? And is there any way to structure my script so that I can?







bash shell-script kill signals






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 23 '17 at 12:40









Community

1




1










asked Dec 5 '12 at 20:11









meetarmeetar

315310




315310







  • 2





    Ctrl+Z does not kill processes, only pauses them. They will keep running if you give the bg of fg commands. Anyway, is there a difference between your 1st and 3d examples?

    – terdon
    Dec 5 '12 at 20:24











  • I don't have timeout on my system but killing sleep works whether it's typed directly on the command line, sourced, executed, or passed through the interpreter explicitly

    – Kevin
    Dec 5 '12 at 21:18











  • @terdon Thanks, I've clarified the examples.

    – meetar
    Dec 8 '12 at 17:28












  • 2





    Ctrl+Z does not kill processes, only pauses them. They will keep running if you give the bg of fg commands. Anyway, is there a difference between your 1st and 3d examples?

    – terdon
    Dec 5 '12 at 20:24











  • I don't have timeout on my system but killing sleep works whether it's typed directly on the command line, sourced, executed, or passed through the interpreter explicitly

    – Kevin
    Dec 5 '12 at 21:18











  • @terdon Thanks, I've clarified the examples.

    – meetar
    Dec 8 '12 at 17:28







2




2





Ctrl+Z does not kill processes, only pauses them. They will keep running if you give the bg of fg commands. Anyway, is there a difference between your 1st and 3d examples?

– terdon
Dec 5 '12 at 20:24





Ctrl+Z does not kill processes, only pauses them. They will keep running if you give the bg of fg commands. Anyway, is there a difference between your 1st and 3d examples?

– terdon
Dec 5 '12 at 20:24













I don't have timeout on my system but killing sleep works whether it's typed directly on the command line, sourced, executed, or passed through the interpreter explicitly

– Kevin
Dec 5 '12 at 21:18





I don't have timeout on my system but killing sleep works whether it's typed directly on the command line, sourced, executed, or passed through the interpreter explicitly

– Kevin
Dec 5 '12 at 21:18













@terdon Thanks, I've clarified the examples.

– meetar
Dec 8 '12 at 17:28





@terdon Thanks, I've clarified the examples.

– meetar
Dec 8 '12 at 17:28










3 Answers
3






active

oldest

votes


















14














Signal keys such as Ctrl+C send a signal to all processes in the foreground process group.



In the typical case, a process group is a pipeline. For example, in head <somefile | sort, the process running head and the process running sort are in the same process group, as is the shell, so they all receive the signal. When you run a job in the background (somecommand &), that job is in its own process group, so pressing Ctrl+C doesn't affect it.



The timeout program places itself in its own process group. From the source code:



/* Ensure we're in our own group so all subprocesses can be killed.
Note we don't just put the child in a separate group as
then we would need to worry about foreground and background groups
and propagating signals between them. */
setpgid (0, 0);


When a timeout occurs, timeout goes through the simple expedient of killing the process group of which it is a member. Since it has put itself in a separate process group, its parent process will not be in the group. Using a process group here ensures that if the child application forks into several processes, all its processes will receive the signal.



When you run timeout directly on the command line and press Ctrl+C, the resulting SIGINT is received both by timeout and by the child process, but not by interactive shell which is timeout's parent process. When timeout is called from a script, only the shell running the script receives the signal: timeout doesn't get it since it's in a different process group.



You can set a signal handler in a shell script with the trap builtin. Unfortunately, it's not that simple. Consider this:



#!/bin/sh
trap 'echo Interrupted at $(date)' INT
date
timeout 5 sleep 10
date


If you press Ctrl+C after 2 seconds, this still waits the full 5 seconds, then print the “Interrupted” message. That's because the shell refrains from running the trap code while a foreground job is active.



To remedy this, run the job in the background. In the signal handler, call kill to relay the signal to the timeout process group.



#!/bin/sh
trap 'kill -INT -$pid' INT
timeout 5 sleep 10 &
pid=$!
wait $pid





share|improve this answer























  • Very sneaky - worked beautifully! I am much smarter now, merci!

    – meetar
    Dec 6 '12 at 17:12


















8














Building on the excellent answer provided by Gilles. The timeout command has a foreground option, if used then a CTRL+C will exit the timeout command.



#!/bin/sh
trap 'echo caught interrupt and exiting;exit' INT
date
timeout --foreground 5 sleep 10
date





share|improve this answer






























    1














    Basically Ctrl+C sends a SIGINT signal, while Ctrl+Z send a SIGTSTP signal.



    SIGTSTP just stops the process, a SIGCONT will continue it.



    This works on the foreground-process that was forked on the command-line.



    If your process is a background-process you will have to send that signal to the processes in a different way. kill will do that. In theory a "-"-operator on that kill should also signal child processes but this seldom works as expected.



    For further reading: Unix-Signals






    share|improve this answer

























    • This is true, at least up to “seldom works as expected” (which depends on your expectations — you should read up about process groups), but completely irrelevant. The question does not betray any confusion about SIGINT and SIGTSTP.

      – Gilles
      Dec 6 '12 at 1:02










    Your Answer








    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "106"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f57667%2fwhy-cant-i-kill-a-timeout-called-from-a-bash-script-with-a-keystroke%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    14














    Signal keys such as Ctrl+C send a signal to all processes in the foreground process group.



    In the typical case, a process group is a pipeline. For example, in head <somefile | sort, the process running head and the process running sort are in the same process group, as is the shell, so they all receive the signal. When you run a job in the background (somecommand &), that job is in its own process group, so pressing Ctrl+C doesn't affect it.



    The timeout program places itself in its own process group. From the source code:



    /* Ensure we're in our own group so all subprocesses can be killed.
    Note we don't just put the child in a separate group as
    then we would need to worry about foreground and background groups
    and propagating signals between them. */
    setpgid (0, 0);


    When a timeout occurs, timeout goes through the simple expedient of killing the process group of which it is a member. Since it has put itself in a separate process group, its parent process will not be in the group. Using a process group here ensures that if the child application forks into several processes, all its processes will receive the signal.



    When you run timeout directly on the command line and press Ctrl+C, the resulting SIGINT is received both by timeout and by the child process, but not by interactive shell which is timeout's parent process. When timeout is called from a script, only the shell running the script receives the signal: timeout doesn't get it since it's in a different process group.



    You can set a signal handler in a shell script with the trap builtin. Unfortunately, it's not that simple. Consider this:



    #!/bin/sh
    trap 'echo Interrupted at $(date)' INT
    date
    timeout 5 sleep 10
    date


    If you press Ctrl+C after 2 seconds, this still waits the full 5 seconds, then print the “Interrupted” message. That's because the shell refrains from running the trap code while a foreground job is active.



    To remedy this, run the job in the background. In the signal handler, call kill to relay the signal to the timeout process group.



    #!/bin/sh
    trap 'kill -INT -$pid' INT
    timeout 5 sleep 10 &
    pid=$!
    wait $pid





    share|improve this answer























    • Very sneaky - worked beautifully! I am much smarter now, merci!

      – meetar
      Dec 6 '12 at 17:12















    14














    Signal keys such as Ctrl+C send a signal to all processes in the foreground process group.



    In the typical case, a process group is a pipeline. For example, in head <somefile | sort, the process running head and the process running sort are in the same process group, as is the shell, so they all receive the signal. When you run a job in the background (somecommand &), that job is in its own process group, so pressing Ctrl+C doesn't affect it.



    The timeout program places itself in its own process group. From the source code:



    /* Ensure we're in our own group so all subprocesses can be killed.
    Note we don't just put the child in a separate group as
    then we would need to worry about foreground and background groups
    and propagating signals between them. */
    setpgid (0, 0);


    When a timeout occurs, timeout goes through the simple expedient of killing the process group of which it is a member. Since it has put itself in a separate process group, its parent process will not be in the group. Using a process group here ensures that if the child application forks into several processes, all its processes will receive the signal.



    When you run timeout directly on the command line and press Ctrl+C, the resulting SIGINT is received both by timeout and by the child process, but not by interactive shell which is timeout's parent process. When timeout is called from a script, only the shell running the script receives the signal: timeout doesn't get it since it's in a different process group.



    You can set a signal handler in a shell script with the trap builtin. Unfortunately, it's not that simple. Consider this:



    #!/bin/sh
    trap 'echo Interrupted at $(date)' INT
    date
    timeout 5 sleep 10
    date


    If you press Ctrl+C after 2 seconds, this still waits the full 5 seconds, then print the “Interrupted” message. That's because the shell refrains from running the trap code while a foreground job is active.



    To remedy this, run the job in the background. In the signal handler, call kill to relay the signal to the timeout process group.



    #!/bin/sh
    trap 'kill -INT -$pid' INT
    timeout 5 sleep 10 &
    pid=$!
    wait $pid





    share|improve this answer























    • Very sneaky - worked beautifully! I am much smarter now, merci!

      – meetar
      Dec 6 '12 at 17:12













    14












    14








    14







    Signal keys such as Ctrl+C send a signal to all processes in the foreground process group.



    In the typical case, a process group is a pipeline. For example, in head <somefile | sort, the process running head and the process running sort are in the same process group, as is the shell, so they all receive the signal. When you run a job in the background (somecommand &), that job is in its own process group, so pressing Ctrl+C doesn't affect it.



    The timeout program places itself in its own process group. From the source code:



    /* Ensure we're in our own group so all subprocesses can be killed.
    Note we don't just put the child in a separate group as
    then we would need to worry about foreground and background groups
    and propagating signals between them. */
    setpgid (0, 0);


    When a timeout occurs, timeout goes through the simple expedient of killing the process group of which it is a member. Since it has put itself in a separate process group, its parent process will not be in the group. Using a process group here ensures that if the child application forks into several processes, all its processes will receive the signal.



    When you run timeout directly on the command line and press Ctrl+C, the resulting SIGINT is received both by timeout and by the child process, but not by interactive shell which is timeout's parent process. When timeout is called from a script, only the shell running the script receives the signal: timeout doesn't get it since it's in a different process group.



    You can set a signal handler in a shell script with the trap builtin. Unfortunately, it's not that simple. Consider this:



    #!/bin/sh
    trap 'echo Interrupted at $(date)' INT
    date
    timeout 5 sleep 10
    date


    If you press Ctrl+C after 2 seconds, this still waits the full 5 seconds, then print the “Interrupted” message. That's because the shell refrains from running the trap code while a foreground job is active.



    To remedy this, run the job in the background. In the signal handler, call kill to relay the signal to the timeout process group.



    #!/bin/sh
    trap 'kill -INT -$pid' INT
    timeout 5 sleep 10 &
    pid=$!
    wait $pid





    share|improve this answer













    Signal keys such as Ctrl+C send a signal to all processes in the foreground process group.



    In the typical case, a process group is a pipeline. For example, in head <somefile | sort, the process running head and the process running sort are in the same process group, as is the shell, so they all receive the signal. When you run a job in the background (somecommand &), that job is in its own process group, so pressing Ctrl+C doesn't affect it.



    The timeout program places itself in its own process group. From the source code:



    /* Ensure we're in our own group so all subprocesses can be killed.
    Note we don't just put the child in a separate group as
    then we would need to worry about foreground and background groups
    and propagating signals between them. */
    setpgid (0, 0);


    When a timeout occurs, timeout goes through the simple expedient of killing the process group of which it is a member. Since it has put itself in a separate process group, its parent process will not be in the group. Using a process group here ensures that if the child application forks into several processes, all its processes will receive the signal.



    When you run timeout directly on the command line and press Ctrl+C, the resulting SIGINT is received both by timeout and by the child process, but not by interactive shell which is timeout's parent process. When timeout is called from a script, only the shell running the script receives the signal: timeout doesn't get it since it's in a different process group.



    You can set a signal handler in a shell script with the trap builtin. Unfortunately, it's not that simple. Consider this:



    #!/bin/sh
    trap 'echo Interrupted at $(date)' INT
    date
    timeout 5 sleep 10
    date


    If you press Ctrl+C after 2 seconds, this still waits the full 5 seconds, then print the “Interrupted” message. That's because the shell refrains from running the trap code while a foreground job is active.



    To remedy this, run the job in the background. In the signal handler, call kill to relay the signal to the timeout process group.



    #!/bin/sh
    trap 'kill -INT -$pid' INT
    timeout 5 sleep 10 &
    pid=$!
    wait $pid






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Dec 6 '12 at 1:01









    GillesGilles

    531k12810631591




    531k12810631591












    • Very sneaky - worked beautifully! I am much smarter now, merci!

      – meetar
      Dec 6 '12 at 17:12

















    • Very sneaky - worked beautifully! I am much smarter now, merci!

      – meetar
      Dec 6 '12 at 17:12
















    Very sneaky - worked beautifully! I am much smarter now, merci!

    – meetar
    Dec 6 '12 at 17:12





    Very sneaky - worked beautifully! I am much smarter now, merci!

    – meetar
    Dec 6 '12 at 17:12













    8














    Building on the excellent answer provided by Gilles. The timeout command has a foreground option, if used then a CTRL+C will exit the timeout command.



    #!/bin/sh
    trap 'echo caught interrupt and exiting;exit' INT
    date
    timeout --foreground 5 sleep 10
    date





    share|improve this answer



























      8














      Building on the excellent answer provided by Gilles. The timeout command has a foreground option, if used then a CTRL+C will exit the timeout command.



      #!/bin/sh
      trap 'echo caught interrupt and exiting;exit' INT
      date
      timeout --foreground 5 sleep 10
      date





      share|improve this answer

























        8












        8








        8







        Building on the excellent answer provided by Gilles. The timeout command has a foreground option, if used then a CTRL+C will exit the timeout command.



        #!/bin/sh
        trap 'echo caught interrupt and exiting;exit' INT
        date
        timeout --foreground 5 sleep 10
        date





        share|improve this answer













        Building on the excellent answer provided by Gilles. The timeout command has a foreground option, if used then a CTRL+C will exit the timeout command.



        #!/bin/sh
        trap 'echo caught interrupt and exiting;exit' INT
        date
        timeout --foreground 5 sleep 10
        date






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Oct 3 '15 at 13:13









        Marwan AlsabbaghMarwan Alsabbagh

        18113




        18113





















            1














            Basically Ctrl+C sends a SIGINT signal, while Ctrl+Z send a SIGTSTP signal.



            SIGTSTP just stops the process, a SIGCONT will continue it.



            This works on the foreground-process that was forked on the command-line.



            If your process is a background-process you will have to send that signal to the processes in a different way. kill will do that. In theory a "-"-operator on that kill should also signal child processes but this seldom works as expected.



            For further reading: Unix-Signals






            share|improve this answer

























            • This is true, at least up to “seldom works as expected” (which depends on your expectations — you should read up about process groups), but completely irrelevant. The question does not betray any confusion about SIGINT and SIGTSTP.

              – Gilles
              Dec 6 '12 at 1:02















            1














            Basically Ctrl+C sends a SIGINT signal, while Ctrl+Z send a SIGTSTP signal.



            SIGTSTP just stops the process, a SIGCONT will continue it.



            This works on the foreground-process that was forked on the command-line.



            If your process is a background-process you will have to send that signal to the processes in a different way. kill will do that. In theory a "-"-operator on that kill should also signal child processes but this seldom works as expected.



            For further reading: Unix-Signals






            share|improve this answer

























            • This is true, at least up to “seldom works as expected” (which depends on your expectations — you should read up about process groups), but completely irrelevant. The question does not betray any confusion about SIGINT and SIGTSTP.

              – Gilles
              Dec 6 '12 at 1:02













            1












            1








            1







            Basically Ctrl+C sends a SIGINT signal, while Ctrl+Z send a SIGTSTP signal.



            SIGTSTP just stops the process, a SIGCONT will continue it.



            This works on the foreground-process that was forked on the command-line.



            If your process is a background-process you will have to send that signal to the processes in a different way. kill will do that. In theory a "-"-operator on that kill should also signal child processes but this seldom works as expected.



            For further reading: Unix-Signals






            share|improve this answer















            Basically Ctrl+C sends a SIGINT signal, while Ctrl+Z send a SIGTSTP signal.



            SIGTSTP just stops the process, a SIGCONT will continue it.



            This works on the foreground-process that was forked on the command-line.



            If your process is a background-process you will have to send that signal to the processes in a different way. kill will do that. In theory a "-"-operator on that kill should also signal child processes but this seldom works as expected.



            For further reading: Unix-Signals







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 2 at 16:29









            kemotep

            2,0913620




            2,0913620










            answered Dec 5 '12 at 21:10









            NilsNils

            12.5k73670




            12.5k73670












            • This is true, at least up to “seldom works as expected” (which depends on your expectations — you should read up about process groups), but completely irrelevant. The question does not betray any confusion about SIGINT and SIGTSTP.

              – Gilles
              Dec 6 '12 at 1:02

















            • This is true, at least up to “seldom works as expected” (which depends on your expectations — you should read up about process groups), but completely irrelevant. The question does not betray any confusion about SIGINT and SIGTSTP.

              – Gilles
              Dec 6 '12 at 1:02
















            This is true, at least up to “seldom works as expected” (which depends on your expectations — you should read up about process groups), but completely irrelevant. The question does not betray any confusion about SIGINT and SIGTSTP.

            – Gilles
            Dec 6 '12 at 1:02





            This is true, at least up to “seldom works as expected” (which depends on your expectations — you should read up about process groups), but completely irrelevant. The question does not betray any confusion about SIGINT and SIGTSTP.

            – Gilles
            Dec 6 '12 at 1:02

















            draft saved

            draft discarded
















































            Thanks for contributing an answer to Unix & Linux Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f57667%2fwhy-cant-i-kill-a-timeout-called-from-a-bash-script-with-a-keystroke%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown






            Popular posts from this blog

            Peggy Mitchell

            Palaiologos

            The Forum (Inglewood, California)