Search code examples
bashshellsh

Alternative for bash's 'read -t' in POSIX shell


I'm currently working on a college project where I have to do several shell script files. In one of them, I have to create a file called taunt.sh that uses the command cowsay to print some messages depending on some actions:

  1. If no message is received after 10 seconds then the taunt.sh script should issue a funny message and finish/exit.
  2. If it receives the SIGHUP signal, then it should issue a special message and exit.
  3. If it receives a SIGINT or SIGTERM, then it should issue a taunt and terminate/exit.

The thing is, I need to use #!/bin/sh and not #!/bin/bash.

I know in bash we can use read -t 10 input to wait for 10 seconds while an input is received, and we could exit of the waiting process after receiving some input.

But this is not an option in sh.

So, is there a way to implement some similar functionality in sh?

I tried this

#!/bin/sh

echo "Enter your input:"
sleep 10 &
read input
kill $! 2>/dev/null

if [ -z "$input" ]; then
  echo "No input provided"
else
  echo "You entered: $input"
fi

But it never got out after 10 seconds, only if I typed something.

I'm pretty new to sh and still takes me a while to understand some things. So I hope somebody can help me with this.


Solution

  • Here a POSIX version of the bash's read -t 10:

    #!/usr/bin/env sh
    
    timeout=10
    mystty="$(stty -g)"
    trap 'stty "$mystty"' EXIT   
    stty -icanon min 0 time $((timeout*10))
    
    echo "Enter your input "
    read input
    
    if [ -z "$input" ]; then
      echo "No input provided"
    else
      echo "You entered: $input"
    fi
    

    • mystty="$(stty -g)" save stty settings in a variable
    • trap 'stty "$mystty"' EXIT: This line set a trap for the EXIT¹ signal. In this case, when the script exits, it will restores those settings in any cases (ctrl+c or any exit cases) for the following terminal modifications :
    • stty -icanon min 0 time 100: This line modifies the terminal settings using the stty command. The -icanon flag disables canonical mode, which means that input is processed immediately, without waiting for a newline character. The min 0 setting means that the terminal will not wait for any characters to be typed before returning input. The time 100 set a timeout of 100 deciseconds (10 seconds) to read input. In this mode, if no input is received within the specified timeout, the read operation will return immediately.

    ¹ POSIX trap exit