3

I'm having trouble getting a trap function in a zsh shell-script to work without exiting the shell. I have a simple countdown timer that I want to be able to interrupt using Ctrl+C, and when I do I want the trap to change the cursor status in the terminal.

My syntax is:

trap 'tput cnorm; exit' INT TERM

I've also tried:

trap 'tput cnorm; kill -9 $$' INT TERM

both interrupts exit the shell entirely. How do I only exit the script and return to the command line?

Any guidance will be most appreciated!


It's a shell script that will be an autoloaded function to be used in an interactive shell when it works.

Here's the entire script:

  #!/bin/zsh

  trap 'tput cnorm; exit' INT TERM

  tput civis

  duration=$(($1 * 60))
  start=$SECONDS
  time=1
  while [ $time -gt 0 ]; do
      output="$((duration - (SECONDS - start)))"
      sleep 1
      output=$(date -d@$time -u +%H:%M:%S)
      echo -ne "  $output     \r"
      done && echo -e "\033[2K"

  tput cnorm
3
  • Are you sourcing your script? Using kill -9 would definitely not be necessary. exit would only exit your shell if you source the script. Use return instead if that's the case. Could you clarify if you're talking about a script, a script that you source, or a shell function that you run in an interactive shell, or whatever it may be?
    – Kusalananda
    Commented Jan 25, 2020 at 17:49
  • I'm sourcing while I update it, but it will be an autoload function running in an interactive shell when it works.
    – Кафка
    Commented Jan 25, 2020 at 20:52
  • Using return 1 solved the issue. Thanks!!
    – Кафка
    Commented Jan 26, 2020 at 21:33

1 Answer 1

4

Are you including the trap within a shell script, or are you typing it on the command line? Consider, for example:

#!/usr/bin/env zsh

interrupted=false
trap 'tput cnorm; interrupted=true' INT TERM

for ((i = 0; i < 100; ++i)); do
    clear
    date
    sleep 1

    if [[ "${interrupted}" = "true" ]]; then
        echo "Interrupted"
        break
    fi
done

With that I mimic a "countdown" with a delay loop that prints the time. I can interrupt the "countdown". I print "interrupted" just for illustration.

$ ./ex.zsh
Sat Jan 25 12:59:12 EST 2020
^CInterrupted
$

My example includes your tput cnorm, but doesn't really need it since I don't do anything to change it to begin with, but I include it to more closely match what you have in your question above.

Is this something close to what you're trying?

4
  • So would it be appropriate to use a break statement rather than an exit?
    – Кафка
    Commented Jan 25, 2020 at 21:17
  • exit will terminate the script. If you want to terminate the script, exit is fine. In my example above I set state that I checked in a loop, and used that to terminate the script. It all depends on what you want to do when. Commented Jan 26, 2020 at 4:32
  • So It works if I make it executable, but this shouldn't be necessary if I use it as an autoload function, right?
    – Кафка
    Commented Jan 26, 2020 at 5:06
  • how to terminate the program started via the zsh script?
    – Niing
    Commented Mar 8, 2022 at 17:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .