Edited at

シェルスクリプトを関数にするか実行可能ファイルにするか

More than 1 year has passed since last update.


悩み


ログイン時の読み込み時間


  • ログイン時には毎回~/.bashrcが読み込まれる。

  • 読み込むものが多いと当然時間がかかる。

  • 実行可能ファイルにしておけば、実行時にパスが通ったところから該当するファイルを探すだけ。

  • 長大なスクリプトは、基本的に実行可能ファイルにすべき。


関数でないとできないこと


現在のシェルに影響を及ぼす


  • 例えば以下のようなコマンド。

cd ~/Documents # ディレクトリを移動

source ~/.bashrc # 設定ファイルを再読み込み


  • これらのコマンドを実行可能ファイル内に記述しても、現在のシェルには反映されない。

  • 実行可能ファイルだと、別プロセスで実行されるため。


現在のシェルを参照する


  • 例えば以下のようなコマンド。

history 2 | head -n 1


  • 関数として実行しなければ、現在のシェルの情報を参照できない。


コマンドを群として管理


  • 関連する小さなスクリプトを大量に書く必要がある場合、関数の方が書くのも管理も楽。

  • 用途ごとに定義ファイルを分けることも可能。


    • 定義ファイルを手動でsourceすることで、任意に有効化することも可能。




実行可能ファイルでないとできないこと


特定のディレクトリでのみ有効なコマンド


  • 環境変数PATHに相対パスを追加することで実現できる。

#~/.bash_profile

export PATH="$PATH:./bin"


スクリプトの編集を即時に反映する


  • 関数だとsourceしなければ変更が反映されないが、ファイルなら保存するだけ。


xargsで引数を得る


そうは言ってもファイルを作るのがめどい


  • 実行可能ファイルを作るスクリプトを作っておくべき。


    • 指定ディレクトリにデプロイとか、

    • 実行権限を付けるとか、

    • shebangを入れるとか、

    • これには入れてないけどパスの通ったディレクトリにシンボリックリンクするとか、



  • 自動化してしまえば思いついたときすぐ作れる。

#!/bin/bash

SHEBANG="#!/bin/bash"
DIRPATH=~/bin
usage () {
echo "Usage: $0 [-i] [language] [-lh]"
}
while getopts li:h OPT
do
case $OPT in
l)
DIRPATH="$(pwd)/bin"
mkdir -p "$DIRPATH" >& /dev/null
;;
i)
case "$OPTARG" in
osa*|ap*)
SHEBANG="#!/usr/bin/osascript"
;;
ru*)
SHEBANG="#!/usr/bin/ruby"
;;
*)
echo "$OPTARG is undifined language" 1>&2
exit 1
esac
;;
h)
usage
exit 0
;;
?)
usage
exit 1
;;
esac
done
shift $((OPTIND - 1))
if [ -n "$1" ];then
NAME="$1"
else
echo "Input script NAME/path" 1>&2
read NAME
if [ -z "$NAME" ]; then
echo "No NAME" 1>&2
exit 1
fi
fi
FILEPATH="$DIRPATH/$NAME"
if [ -f "$FILEPATH" ];then
echo "Same file is existing" 1>&2
exit 1
fi
if [ ! -d "$(dirNAME "$FILEPATH")" ]; then
mkdir -p "$(dirNAME "$FILEPATH")"
fi
touch "$FILEPATH" && chmod +x "$FILEPATH" && ( echo "$SHEBANG"; echo "" ) > "$FILEPATH"
mvim +2 "$FILEPATH"