シェルスクリプトを書くときの頻出コードメモ
Linuxを使っているのでインストールや環境構築でシェルスクリプト (bash )をよく書きます。 シェルスクリプトだと様々な表現が可能なのですが、他言語と違い適当にかけないことが多々あるのでよくググる頻出コードをまとめておきます。
起動スクリプトのパスを取得
インストールや環境構築で使うことが多いのでスクリプトファイルからの相対パスを使いたい場合が多いです。Pythonであればos.path.dirname(__file__)
にて簡単にとることができるのですがシェルスクリプトの場合は下記のようになります。
# 一行で書く方法 ROOT=$(cd $(dirname $0);pwd) # わかりやすい書き方 ROOT=`dirname $0` ROOT=`cd $ROOT;pwd` # 使用例(スクリプトファイルと同位置にあるvimrcを~/.vimrcにリンク) ln -sf $ROOT/vimrc $HOME/.vimrc
ファイル・ディレクトリ・アプリケーションの存在確認
特にアプリケーションの存在確認が面倒
# ファイルの存在確認 if [ -f "~/.vimrc" ]; then echo "きゃー" fi if [ ! -f "~/.vimrc" ]; then # 別に先の if の else でいいけど否定の例として echo "Emacs使いですか、そうですか。念の為に vim をいんすとーるしておきますね。" yes | sudo apt-get install vim fi # ディレクトリの存在確認 if [ -d "~/.vim" ]; then echo "イケメンよ!" else echo "・・・あれ?" echo "念の為に vim をいんすとーるしておきますね。" yes | sudo apt-get install vim fi # アプリケーションの存在確認 which vim > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "抱いて!" else echo "さようなら" echo "・・・" yes | sudo apt-get install vim fi # アプリケーションの存在確認(簡易版 - 逆になるので注意) if type vim > /dev/null 2>&1 then echo "さようなら" echo "・・・" yes | sudo apt-get install vim else echo "抱いて!" fi
プラットフォームによる処理の分離
僕はLinux (Debian)とMacを使用しているのでパッケージマネージャなどを変更する必要があります。
そのような場合は下記のようにuname
によりプラットフォーム分離を行なっています。
UNAME=`uname` # -r でバージョン, -p でアーキテクチャにも使用可 if [ "$UNAME" = "Darwin" ]; then # Homebrewを使ってる前提ですね(笑 brew install macvim elif [ "$UNAME" = "Linux" ]; then # 本当はプログラムの存在等で分岐させるべき # だけど Debian しか基本的に使用しないので sudo apt-get install gvim fi
ユーザーに入力を求める(Yes / No)
なにか続行してもいいですか?系を聞くときの頻出表現。ループさせることで変な値入れても再度聞きなおすようにしている。
# 関数で定義しちゃったほうが楽。 # シェルの返り値は基本的には終了コードと同一の扱いなので # Yesのときは0、Noのときは1を返すようにしている。 # ちなみに文字列を返したい場合は print して `` で実行する。 # 別に返してるわけじゃないけどね! askYesOrNo() { while true ; do read -p "$1 (y/n)?" answer case $answer in [yY] | [yY]es | YES ) return 0;; [nN] | [nN]o | NO ) return 1;; * ) echo "Please answer yes or no.";; esac done } # 使い方 askYesOrNo "Vim をインストールしますか?" if [ $? -eq 0 ]; then # シェルスクリプトの返り値は終了コードを取る`$?`で取得 yes | sudo apt-get install vim else echo "Emacs派ですか、そうですか。念のためインストールしておきますね。" yes | sudo apt-get install vim fi
複数の番号から処理を選択させる場合
のように番号でインストールしたいものを選ばせる場合などは下記のようにすればOK
while true; do cat <<EOF Which editor do you want me to install? 1. Vim 2. GVim 3. Emacs 4. Nano EOF read ACTION case ${ACTION} in 1) yes | sudo apt-get install vim break;; 2) yes | sudo apt-get install gvim break;; 3) yes | sudo apt-get install emacs break;; 4) yes | sudo apt-get install nano break;; *) echo "Please input the number";; esac done
配列に追加していき一気に処理する
インストール候補を選択させて最後に一気にインストールとかするときに使う。 シェルスクリプトの配列は若干面倒…
INSTALL_LIST=("vim") # vim は初期値、空でもOK `INSTALL_LIST=()` askYesOrNo "Emacsをインストールしますか?" if [ $? -eq 0 ]; then INSTALL_LIST=("${INSTALL_LIST[@]}" "emacs") fi # zshを追加 (2013-07-08 10:00 修正) INSTALL_LIST=("${INSTALL_LIST[@]}" "zsh") # (ry # 全部インストール(例なのでforで回してみる) for INSTALL in ${INSTALL_LIST[@]}; do yes | sudo apt-get install $INSTALL done
(番外)GithubのREADMEとかで一行インストールコマンドを書く
Debian系(wget存在)の場合
% wget $URL -O - | bash
Darwin系(curl存在)の場合
% curl $URL | bash
なお記事全体を通してEmacsをdisってるように見えるかもしれませんが気のせいです。 筆者はEmacsを使ったことがないのでdisれません。ごめんなさい。