Search code examples
bashreadlinebash-builtins

How do I catch return characters when using character-at-a-time BASH builtin read with if or a case statement?


I stumbled across what should be something simple that's turned out to be a brain-teaser. As a not fully accomplished BASH programmer, I naively thought I could read in characters from an interactive terminal window and actually determine what keys were pressed! MOST keys work out just fine, but how to catch "return" is non-obvious.

Here's some sample code to illustrate the question:

   while [ $justRead != "\n" ] ;
   do
      # read -e -s -N 1 justRead
      read -s -N 1 justRead
      case "$justRead" in
         \n | "\n" | \r | "\r" | ^M | '^M')
            echo  "return"
         ;;
         *)
            echo -n "$justRead"
         ;;
      esac
   done

As can be seen, the code has a line using the Readline library and another that does not. The two behave differently but I've not gotten either to work successfully. I'm SURE it's something I'm doing wrong with my match string.

I also noticed that the -s - silent - option appears to be ignored by Readline but not the other library, not that that matters to the question, I was just surprised by that.

OBVIOUSLY I'm missing something here! This just has to be simple, right?

Please! Just fixing the syntax does NOT help educate! Please explain WHY your fix works.


Solution

  • The solution is to use the ANSI C quoting method that can be found here. The dollar-sign followed by a single-quoted string is a special case, as documented there and is apparently used in BASH.

       while [ justRead != "\n" ] ;
       do
          # read -e -s -N 1 justRead
          read -s -N 1 justRead
          case "$justRead" in
             $'\n')
                echo  "return"
             ;;
             *)
                echo -n "$justRead"
             ;;
          esac
       done