bashのシェルスクリプトで、ターミナルのウィンドウサイズやカーソルの現在位置を取得させたいということがあったので、備忘で残しておく。

1. ターミナルのサイズを取得する

ターミナルのサイズを取得するのは簡単で、bashでcheckwinsizeが有効になっていれば$LINES、$COLUMNS変数に値が入る。

#!/bin/bash
shopt -s checkwinsize; (:;:)

echo $LINES # 行数
echo $COLUMNS # 横の文字数

ちなみに、数字は1から数えての数になっている。

2. カーソルの現在位置を取得する

現在のターミナル上のカーソル位置を取得する場合は、ANSIエスケープを利用する。 ANSIエスケープで「\e[6n」を出力させると、「ESC[n;mR」(キャレット記法だと「^[[n;mR」)という出力で現在のカーソル位置を取得できる。 これはnが行数、mが列数になっている(ちなみに0から数えた数)。

スクリプト上で現在のカーソル位置を取得する場合、端末が払い出されない場合(パイプ越しに実行した場合)でも動作するよう、以下のようにttyを別に用意して数えるのがいいようだ。

# @brief: get cursor positon
# @return: $row $col
function __get_cursor_position() {
  exec < /dev/tty
  local OLD_STTY=$(stty -g)
  stty raw -echo min 0

  # get position data
  echo -ne "\e[6n" > /dev/tty
  IFS=';' read -r -d R -a POSITION
  stty ${OLD_STTY}

  # parse row and column
  local POS_ROW=${POSITION[0]:2}
  local POS_COL=${POSITION[1]}
  echo ${POS_ROW} ${POS_COL}
}

上のような関数を設定しておけば、関数実行時にカーソル位置を取得することができる。