Linuxのコマンド登録可能なメニュー処理シェルスクリプト

近頃Linux関連の書籍を少し読んでいるが、コマンドとオプションを覚えきれないで、困っていた。
そこで試みに、メニュー形式でコマンド実行できるシェルスクリプトを組んでみた。
だが、まだ完成していない。

機能は以下。
・メニューリストから番号を入力してコマンド実行。
・コマンドはメニューに別の表題をつけて表示される。(日本語メニュー)
・コマンド実行時、そのコマンド出力の内容のヘルプテキスト表示可能。
・コマンドとメニュー表題を追加・削除可能。
・サブメニュー選択可能。(まだサブメニューは追加編集はできない)
・サブメニューはまだ1階層しか実現できない。

例えば、上記プロンプトに「1」と番号を入力すると、
「sar -u」が実行される。

shのスクリプトソースは以下。

#!/bin/sh

CONFDIR="menu.sh.conf"

MAINMENU="${CONFDIR}/menutext.txt"
MAINCMD="${CONFDIR}/menucmd.txt"
SUBMENUTEXT="${CONFDIR}/menusubtext"
SUBMENUCMD="${CONFDIR}/menusubcmd"
HELPFN="${CONFDIR}/menuhelp"
SUBHELPFN="${CONFDIR}/menusubhelp"

#メニュー描画
#menutext.txtを読み込んで加工し表示する
#$1 : メニューテキスト(行頭#行はコメント)
#$2 : ヘッダー表示フラグ(メインメニュー=""、サブメニュー="Snn")
function drawmenu()
{
    #ヘッダー表示
    if [ -n "$2" ]; then
	#サブメニュー
	T=`cat $MAINMENU | grep -i $2 | cut -d : -f 2 -`
	echo "2=$2"
	echo "T=$T"
	echo "+++ [Sub] $T +++"
    else
	echo "*** メインメニュー ***"
    fi
 
    #menutext.txt の各行をxargsで引数に変換し、Lに1行ずつ代入。
    #このとき、スペースはに変換している。(xargsに1行を1つの引数と認識させるため)
    for L in `cat $1 | sort | grep -iv "^[#0-9]" | sed "s/[ ]//g" | sort | xargs`; do
	#L中のを半角スペースに戻す。
	L=`echo $L | sed "s// /g"`

	#Lに入っている行文字列の先頭に*を加え表示
	echo "* $L"
    done
    for L in `cat $1 | grep -iv "^[#sSnN]" | sed "s/[ ]//g" | sort | xargs`; do
	#L中のを半角スペースに戻す。
	L=`echo $L | sed "s// /g"`

	#Lに入っている行文字列の先頭に*を加え表示
	echo "* $L"
    done
    if [ $1 = $MAINMENU ]; then
	echo "* 999:終了"
    else
	echo "* 999:メインメニューへ戻る"
    fi
}

#Y/Nチェック
function yesno()
{
    read -n 1 -p $1 A
    echo
    if [ $A = 'Y' -o $A = 'y' ]; then
	return 0
    fi
    if [ $A = 'N' -o $A = 'n' ]; then
	return 1
    fi
    return 2
}

#pause
function anykey()
{
    read -n 1 -p '何かキーを押してください。'
}


#メニューのコマンドを実行
#$1 : コマンド番号(001〜)
#$2 : コマンド登録テキストファイル(タブ区切り2列、先頭#行はコメント)
function docommand()
{
    #echo $1 $2
    #コマンド抽出
    C=`grep -v "^#" $2 | grep $1 | cut -f 2 -`
    echo "C=$C"
    #コマンドが存在した場合のみ実行
    if [ -n "$C" ]; then
	eval $C
    fi
}

#コマンド作成
function makecmd()
{
    while : 
      do
	read -p '実行コマンドの表題を入力してください。(C[キャンセル])> ' T
	if [ "$T" = "C" ]; then
	    echo "キャンセルしました。"
	    return 1;
	else
	    break
	fi
    done

    while :
      do
	read -p '実行コマンドを入力してください。(C[キャンセル])> ' C
	if [ "$C" = "C" ]; then
	    echo "キャンセルしました。"
	    return 1;
	else
	    break
	fi
    done

    echo "コマンドのヘルプを入力してください。(Ctrl+D[入力完了],C+CtrlD[キャンセル])"
    TMPFN="/tmp/menu.sh.tmp.$$"
    cat - > $TMPFN
    H=`cat $TMPFN`
    if [ "$H" = "C" ]; then 
	    echo "キャンセルしました。"
	    return 1;
    fi

    CUR=`cat $MAINMENU | grep "^[0-9]" | sort -r | head -1 | cut -d : -f 1 -`
    NEXT=`expr $CUR + 1`
    NEXT=`echo $NEXT | awk '{ printf("%03d",$0);}'`

    echo "$NEXT:$T" >> $MAINMENU
    echo -e $NEXT \\t $C >> $MAINCMD
    echo $H > ${HELPFN}_${NEXT}.txt
}

function removecmd()
{
    read -p '削除するコマンド番号を入力してください。(C[キャンセル])> ' A
    if [ "$A" = "C" -o "$A" = "c" ]; then
	echo "キャンセルしました。"
	return 1
    fi
    if echo $A | grep "^[^0-9]"; then
	echo "キャンセルしました。"
	return  1
    fi
    S=`echo $A | awk '{printf("%03d",$0);}'`

    echo "S=$S"

    TEMPFN="/tmp/menu.sh.removefile.tmp.$$"
    cat $MAINMENU | grep -v "^$S" > $TEMPFN
    cat $TEMPFN > $MAINMENU

    cat $MAINCMD | grep -v "^$S" > $TEMPFN
    cat $TEMPFN > $MAINCMD


}

#ヘルプの表示
#$1 : コマンド番号
#$2 : MENUFLAG
function printhelp()
{
    if [ -n "$2" ]; then
	#サブメニュー
	FN="${SUBHELPFN}_$2_$1.txt"
    else
	FN="${HELPFN}_$1.txt"
    fi

    if [ -f "$FN" ]; then
	cat $FN
    fi
}

function Nproc()
{
    if [ "$1" = "00" ]; then
	echo "新規メニューを作成します。"
	anykey
	makecmd
	anykey
    fi
    
    #N9 : サブメニューを削除
    if [ "$1" = "09" ]; then
	echo "メニューを削除します。"
	anykey
	removecmd
	anykey
    fi	
}

ER=1

CMENU=$MAINMENU
CCMD=$MAINCMD
MENUFLAG=""

while [ $ER = 1 ]; do
    clear
    drawmenu $CMENU $MENUFLAG
    read -p '番号入力> ' A
#    echo "A=$A"
    #999番は終了か、サブメニューからメインメニューに戻る
    if [ $A = 999 ]; then
	if [ $CMENU = $MAINMENU ]; then
	    echo "終了します。"
	    exit 0;
	else
	    MENUFLAG=""
	    CMENU=$MAINMENU
	    CCMD=$MAINCD
	    continue
	fi
    fi
    
    #Nnn番はコマンドを新規作成など特殊メニュー
    if echo $A | grep -i "^n"; then
	#echo "サブメニュー"
	#N0 : サブメニュー番号をSに取得
	S=`echo $A | sed -e "s/n\([0-9]*\)/\1/i" | awk '{printf("%02d",$0);}'`
	Nproc $S
	continue
    fi

    if echo $A | grep -i "^s"; then
	#echo "サブメニュー"
	#サブメニュー番号をSに取得
	S=`echo $A | sed -e "s/s\([0-9]*\)/\1/i" | awk '{printf("%02d",$0);}'`

	#サブメニューのテキストファイル名を取得
	SUBTEXTFN="${SUBMENUTEXT}_${S}.txt"
	#echo "S=${SUBMENUTEXT}_${S}.txt"

	#サブメニューファイルが存在するか?
	if [ -f $SUBTEXTFN ]; then
	    #存在する
	    #メニューをサブメニューに切り替え
	    MENUFLAG="S$S"
	    CMENU="${SUBMENUTEXT}_${S}.txt"
	    CCMD="${SUBMENUCMD}_${S}.txt"
	else
#	    echo "SUBTEXTFN=$SUBTEXTFN"
	    echo "指定されたサブメニューは存在しません。"
	fi
	anykey
	continue
    fi

    #コマンド番号をAに取得
    A=`echo $A | awk '{printf("%03d",$0);}'`
    #echo $A

    #ヘルプ表示
    printhelp $A $MENUFLAG

    #コマンド実行
    echo docommand $A $CCMD
    docommand $A $CCMD 
    anykey
done

以下、メニュー用テキストファイルの内容。(menutext.txt)

N00:新規メニュー作成
N09:メニュー削除
001:CPUの使用率や使用時間帯を調べたい(sar -u)
#bb
002:キューの長さと使用された時間の割合を調べたい(sar -q)
003:発行されたシステムコールの回数を調べたい(sar -c)
S01:サブメニュー1

以下、コマンド用テキストファイルの内容(menucmd.txt)

001	sar -u 1 5
002	sar -q 1 5
003	sar -c 1 5