grepコマンドが優しくない
ファイルの中の文字列を検索する「grep」コマンド。
使用頻度がかなり高いとは思いますけど、どうにも優しくない。
優しくなさすぎて「find」コマンドと併用したりしてしまいがち。
「find」は、それはそれでコマンド行が長くなりがちなので、ここはひとつシェルスクリプトで補完してみようじゃないかと思いたちました。
まずは、デフォルト状態を決めます。
- ヒットしなかった行は表示しない
- 標準でカラーモード
- ヒットした行番号を表示する
- 指定ディレクトリのファイルすべてが対象
- でもファイルの拡張子は指定したい
というわけで実装してみます。
オプション処理
bashでのオプション処理と言えば「getopts」ですが、欠点としてよく挙げられているのが「オプション以外の引数の後ろにオプションを指定出来ない」というものがあります。
しかし、getoptsが無効なオプションが出てきたらそこで処理を止めているだけで、オプション引数にはちゃんと格納されています。
なので、
- getoptsでループを廻しオプション処理をする
- ループを抜けたら処理した引数の数(オプションの数ではない)だけ「shift」する
ただし、オプション以外の引数の前にオプション指定がなかった場合はこの数が「0」なので、ひとつだけ「shift」させる - 「$1」を引数として取り出す
- 「$1」が空だった場合はオプション処理終了
という形にすると、オプションとオプション以外の引数を混在させられます。
対象ディレクトリ
grepする場合は、大抵がディレクトリ内の全ファイルが対象なので、ファイルの指定は基本的には「」(ワイルドカード)にする。
ディレクトリ指定がなかった場合はカレントディレクトリの「」、ディレクトリが指定されていた場合はそのディレクトリの「*」を対象にします。しかし、ファイルの種類だけでも指定出来ると便利なので「拡張子」を指定出来るようにしました。
スクリプト
そして出来たのがこちらになります。
#!/usr/bin/env bash
CMD=`basename $0`
#=============================================================================
# error handler
# エラー処理
#=============================================================================
function error() {
case ${1} in
[12] )
echo "Usage:"
echo "$CMD [-r] [-e ext] [other grep option] search_string [search_directory]"
echo "-r : Recursive"
echo "-e ext: Limits the search to files with the specified extension."
echo ""
;;
[34] )
echo "require option parameter."
echo ""
;;
[5] )
echo "invalid option - '${2}'"
echo ""
;;
esac
exit
}
#=============================================================================
# option procedure
# オプション制御
#=============================================================================
function optproc() {
local OPT OPTARG
OPT=$1
OPTARG=$2
case $OPT in
[e] )
if [ -z "$OPTARG" ] || [ ${OPTARG:0:1} = "-" ]; then
error 3
else
OPTION="$OPTION --include *.$OPTARG"
fi
;;
[r] )
RECURSIVE="-R"
TARGET=""
;;
[C] )
if [ -z "$OPTARG" ] || [ ${OPTARG:0:1} = "-" ]; then
error 4
else
OPTION="$OPTION -C$OPTARG"
fi
;;
[\?] )
error 5 $OPTARG
;;
[:] )
;;
* )
OPTION="$OPTION -$OPT"
;;
esac
}
#=============================================================================
# main procedure
# メイン処理
#=============================================================================
#---------------------------
# exec without option
# オプションなしで実行
#---------------------------
if [ -z "${1}" ]; then
error 1
fi
#---------------------------
# variable
# 変数
#---------------------------
COMMAND="/usr/bin/env grep"
OPTION="--color=auto -Isn"
RECURSIVE=""
TARGET="*"
SEARCH=""
#---------------------------
# option loop
# オプションでループ
#---------------------------
arg="-"
argarr=()
#---------------------------
# valid option
# 有効なオプション
#---------------------------
option=":lvire:C:VcLo"
IFS=$'\n'
while [ ! -z $arg ]; do
while getopts $option OPT; do
optproc $OPT $OPTARG
done
num="$(($OPTIND-1))"
shift $num
arg=$1
if [ ! -z "$arg" ]; then
argarr+=($arg)
OPTIND=1
shift
fi
done
SEARCH=${argarr[0]}
if [ -z $SEARCH ]; then
error 4
fi
num=${#argarr[*]}
DIRTMP=""
for i in $(seq $num); do
argstr=${argarr[$i]}
if [ ! -z "$argstr" ]; then
DIRTMP="$DIRTMP $argstr"
fi
done
IFS=$' '
if [ ! -z "$DIRTMP" ]; then
DIRECTORY=${DIRTMP%/}
TARGET="$DIRECTORY/$TARGET"
fi
$COMMAND $SEARCH $RECURSIVE $OPTION $TARGET
結構、汎用的には作ってあるので、シェルスクリプトの雛形としてお使いください。