シェルスクリプトでキー入力のイベントを受け取る


read -t NのPOSIXシェルの範囲内でできる代替って無いのかなというのは以前から気になってたので、このやりとりを見つけてかなりすっきりしました。

mintimeはたしかにPOSIXに記載があります。
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/stty.html

ここで紹介されていた方法を応用すると、ゲームっぽいものもつくれそうな気がします。

#!/bin/sh

getch() {
  old=$(stty -g)
  stty raw -echo min 0 time 1
  printf '%s' $(dd bs=1 count=1 2>/dev/null)
  stty $old
}

print_aa() {
  _pos="${1}"
  _state="${2}"
  if [ "${_state}" = "0" ]; then
    _format="% ${_pos}s\\(^q^)/"
  elif [ "${_state}" = "1" ]; then 
    _format="% ${_pos}s/(^q^)\\"
  fi
  printf "${_format}"
}

pos=0
aa_state=0
aa_state_change_count=0

clear
print_aa "${pos}"

while :; do
  c=$(getch)
  case ${c} in
    "q" )
      break
      ;;
    "h" )
      [ "${pos}" -gt 0 ] && pos=$((pos-1))
      ;;
    "l" )
      [ "${pos}" -lt 30 ] && pos=$((pos+1))
      ;;
    * )
      ;;
  esac
  if [ "${aa_state_change_count}" -lt 4 ]; then
    aa_state_change_count=$((aa_state_change_count + 1))
  else
    aa_state_change_count=0
    if [ "${aa_state}" = "0" ]; then
      aa_state=1
    else
      aa_state=0
    fi
  fi
  clear
  print_aa "${pos}" "${aa_state}"
done

clear

hを押すと左に、lを押すと右に、qを押すと終了します。

入力がある場合も最低何ミリ秒待つみたいなことができそうにないので、本当にゲームをつくるのは厳しいかも。