スクリプト言語のプログラム(ruby, pythonなど)を、shスクリプトからexec ruby hoge.rb "$@"
として呼び出す場合に考慮すべき点をまとめました。
(rubyコードの先頭行に#!/usr/bin/ruby
書いて、インタプリタ起動するのとは違います)
shスクリプトがシンボリックリンクでも動作するように、スクリプト言語のあるパスを取得する必要があります。
サンプル
コマンドラインで渡された引数を標準出力に表示するrubyプログラム(echo_args.rb)を、shスクリプト(echo_args)から実行します。
ファイル構成
echo_args
|- bin/
| echo_args # rubyプログラム実行スクリプト
|- lib/
| echo_args.rb # rubyスクリプト
ソース
echo_args.rb
ARGV.each {|s| puts s}
echo_args
#!/bin/sh
# 自身の絶対パスを取得する
ECHO_ARGS_FILE_DIRECTORY=$(cd ${0%/*} && pwd -P)
# 実行しているのはリンク?
## リンクの場合、readlinkの戻り値が変数に入る
ECHO_ARGS_SYMLINK=$(readlink "$0")
if [ -n "$ECHO_ARGS_SYMLINK" ]
then
ECHO_ARGS_SYMLINK_DIRECTORY=$(dirname "$ECHO_ARGS_SYMLINK")
ECHO_ARGS_FILE_DIRECTORY=$(cd $ECHO_ARGS_FILE_DIRECTORY &&
cd $ECHO_ARGS_SYMLINK_DIRECTORY && pwd -P)
fi
# rubyプログラムのパスを取得
ECHO_ARGS_LIBRARY_DIRECTORY=$(cd $ECHO_ARGS_FILE_DIRECTORY/../lib && pwd -P)
# rubyプログラムを実行する
exec ruby "${ECHO_ARGS_LIBRARY_DIRECTORY}/echo_args.rb" "$@"
ポイント
- 自身がリンクかどうかはreadlinkコマンドで判断する
- 実行されたリンクが相対パスだった場合を考慮、
自身のパスを取得して、そこを基点とする
実行例
shスクリプトが、非リンク、絶対/相対パス指定のリンク、いずれの場合も意図したとおりに動作しました。
% pwd
/Users/yampro/Dropbox/src/ruby/echo_args/bin
% ll
total 8
-rwxr-xr-x@ 1 echo_args*
★非リンクの場合(スクリプト実体)
% ./echo_args taniguchi marui
taniguchi
marui
% pwd
/Users/yampro/bin
% ll
lrwxr-xr-x 1 linka@ -> /Users/yampro/Dropbox/src/ruby/echo_args/bin/echo_args
lrwxr-xr-x 1 linkb@ -> ../Dropbox/src/ruby/echo_args/bin/echo_args
★linkaが絶対パス、linkbが相対パスのシンボリックリンク
★絶対パス指定したリンクの場合
% ./linka igarashi iguchi
igarashi
iguchi
★相対パス指定したリンクの場合
% ./linkb kondo makino
kondo
makino
参考にしたもの
- Homebrewの実行スクリプト
メモ
- GNU版のreadlinkは
-f
でリンク元のフルパスは取得できるが、
BSD版(Mac)にはないので使わなかった
(使えば、分岐なしにシンプルに書ける) -
$0
: 実行しているコマンドの実行パス(相対) -
$@
: シェルスクリプトに渡されたすべての引数 -
exec
: 子プロセスを生成せずに、コマンドを実行する