私はシェルスクリプトの大ファンで、他人のスクリプトから面白い方法を学ぶのが大好きだ。最近、SSHサーバの2要素認証を簡単にするためのauthy-sshスクリプトに出会った。このスクリプト群を見まわしていて、みんなと共有したいたくさんのクールなことを見つけた。
出力に色付けする
出力文字列を、成功した時は緑に、失敗した時は赤に、警告は黄色に色づけしたいと思うことはたくさんあるだろう。
NORMAL=$(tput sgr0)
GREEN=$(tput setaf 2; tput bold)
YELLOW=$(tput setaf 3)
RED=$(tput setaf 1)
function red() {
echo -e "$RED$*$NORMAL"
}
function green() {
echo -e "$GREEN$*$NORMAL"
}
function yellow() {
echo -e "$YELLOW$*$NORMAL"
}
# 成功
green "Task has been completed"
# エラー
red "The configuration file does not exist"
# 警告
yellow "You have to use higher version."
tput
を使うと、色の設定、文字の配置、色のリセットができる。tput
について詳しくはprompt-color-using-tputを参照しよう。
デバッグ情報を表示する
デバッグフラグがセットされている時だけ、デバッグ情報を表示してみる。
function debug() {
if [[ $DEBUG ]]
then
echo ">>> $*"
fi
}
# 何かデバッグメッセージ
debug "Trying to find config file"
イケてるギークは1行でデバッグ用関数を書いてしまうようだ。
# hacker newsで見かけたとあるイケてるギークによる
function debug() { ((DEBUG)) && echo ">>> $*"; }
function debug() { [ "$DEBUG" ] && echo ">>> $*"; }
指定した実行ファイルが存在しているかどうかチェックする
OK=0
FAIL=1
function require_curl() {
which curl &>/dev/null
if [ $? -eq 0 ]
then
return $OK
fi
return $FAIL
}
which
コマンドでcurl
の実行ファイルを探している。コマンドが成功したら、実行ファイルは存在していることになるし、失敗すれば存在していなかったことになる。&>/dev/null
は、標準出力と標準エラー出力を`/dev/null
に送ってしまう(つまり、コンソールには何も出さない)。
別のイケてるギークはwhich
コマンドの戻り値を直接返してしまうこともできると教えてくれた。
# hacker newsで見かけたとあるイケてるギークによる
function require_curl() { which "curl" &>/dev/null; }
function require_curl() { which -s "curl"; }
スクリプトの使用方法を表示する
私がシェルスクリプトを始めた頃は、スクリプトの使用方法を表示するのにechoコマンドを使っていた。使用方法が長くなると、echoコマンドがごちゃごちゃしてきてしまう。それで、cat
コマンドを使って表示すればいいと気づいた。
cat << EOF
Usage: myscript <command> <arguments>
VERSION: 1.0
Available Commands
install - Install package
uninstall - Uninstall package
update - Update package
list - List packages
EOF
<<
はヒアドキュメントと呼ばれる仕組みだ。2つのEOFの間の文字列を扱う。
ユーザ指定の値とデフォルト値の扱い
ユーザが値を指定しなかった時、デフォルト値を使いたいことはよくあるだろう。
URL=${URL:-http://localhost:8080}
この例の場合、URLという環境変数をチェックして、それが存在しなかった場合はlocalhost
をURLに割り当てる。
文字列の長さを判定する
if [ ${#authy_api_key} != 32 ]
then
red "不正なAPIキーです"
return $FAIL
fi
${#変数名}
で変数の長さを得られる。
タイムアウト付きで入力を待ち受ける
READ_TIMEOUT=60
read -t "$READ_TIMEOUT" input
# 引用符が不要ならエスケープしよう
input=$(sed "s/[;\`\"\$\' ]//g" <<< $input)
# 数字を入力するなら、他の文字をエスケープすることも可能
input=$(sed 's/[^0-9]*//g' <<< $input)
ディレクトリ名やファイル名を得る
# ベースディレクトリを取得
APP_ROOT=`dirname "$0"`
# ファイル名を取得
filename=`basename "$filepath"`
# 拡張子抜きのファイル名を取得
filename=`basename "$filepath" .html`
ハッピースクリプティング、そしてよい一日を。