序
私はscriptをよく使うのだが、scriptが走るときに具体的に何が起こっているのかを確認したいと思って、いくつか実験してみた。
(注意!!以下は、FreeBSDでの話です。)
実験1
スクリプト:hoge.scm#!/usr/local/bin/gosh
(define (main args)
(print args))
$ aho.scm
$ hoge.scm
(./hoge.scm)
$ gosh hoge.scm
(./hoge.scm)
実験2a
スクリプト:hoge.echohoge.echo
#!/usr/bin/echo
This is echo.
$ ./hoge.echo 1 2 3
./hoge.echo 1 2 3
$ echo ./hoge.echo 1 2 3
./hoge.echo 1 2 3
実験2b
スクリプト:hoge.echo#!/usr/bin/echo -n
This is echo.
$ ./hoge.echo 1 2 3
./hoge.echo 1 2 3(改行なし)
$ echo ./hoge.echo 1 2 3
./hoge.echo 1 2 3(改行あり)
実験2c
スクリプト:hoge.echo#!/usr/bin/echo -n that is echo
This is echo.
$ ./hoge.echo 1 2 3
-n that is echo ./hoge.echo 1 2 3
$ echo ./hoge.echo 1 2 3
./hoge.echo 1 2 3
しかし、echoはスクリプト名を引数として受け取ることは想定していないので、
$ echo filename
実験3a
スクリプト:hoge.c -> コンパイルしたものは hoge#include < stdio.h >
int main(int argc, char **argv){
int i;
for(i=0; i;< argc; i++){
printf("argv[%d]=%s\n", i, argv[i]);
}
return 0;
}
$ ./hoge 1 2 3
argv[0]=./hoge
argv[1]=1
argv[2]=2
argv[3]=3
実験3b
スクリプト:hoge.hoge#!./hoge
$ ./hoge.hoge 1 2 3
argv[0]=./hoge
argv[1]=./hoge.hoge
argv[2]=1
argv[3]=2
argv[4]=3
実験3c
スクリプト:hoge.hoge#!./hoge -s
$ ./hoge.hoge 1 2 3
argv[0]=./hoge
argv[1]=-s
argv[2]=./hoge.hoge
argv[3]=1
argv[4]=2
argv[5]=3
実験3d
スクリプト:hoge.hoge#!./hoge -s witch
$ ./hoge.hoge 1 2 3
argv[0]=./hoge
argv[1]=-s witch
argv[2]=./hoge.hoge
argv[3]=1
argv[4]=2
argv[5]=3
実験4
スクリプト:hoge.awk#!/usr/bin/awk -f
BEGIN{
for (i=0; i < ARGC; i++){
print "ARGV[" i "]=" ARGV[i]
}
}
$ hoge.awk 1 2 3
ARGV[0]=/usr/bin/awk
ARGV[1]=1
ARGV[2]=2
ARGV[3]=3
$ awk -f hoge.awk 1 2 3
ARGV[0]=awk
ARGV[1]=1
ARGV[2]=2
ARGV[3]=3
結論
スクリプト:script#! <interpeter> <arg>
---
---
$ script argv1 argv2
裏では、(forkした後に)
argv[0] = <interpreter>
argv[1] = <arg>
argv[2] = script
argv[3] = argv1
argv[4] = argv2
として、execが実行される。(ただし、<arg>が空の時には、
argv[0] = <interpreter>
argv[1] = script
argv[2] = argv1
argv[3] = argv2
と一個ずれる。)別の書き方をすれば、次のようになる。
execve("script", "argv1", "argv2")
↓(shellが、scriptの最初の2バイトを読んで「scriptだ!」と気づく)あらためて、
execve("<interpreter>", "<arg>", "script", "argv1", "argv2")
する。スクリプト中の一行目の<args>はひとまとまりとして、<interpreter>に渡される。
したがって、<args>が空白で区切られたいくつかのフレーズを含んでも正しく解釈されない。
空白を含まないオプションを一つだけ与えたときのみ、意図した動きをする。
(実験2と実験3、/usr/src/bin/echo/echo.c)
interpreterがいわゆるスクリプト言語の場合は、argv1以降だけにトリミングして渡してくれるているので、interpreterにscriptを渡すのと、scriptを直接実行するので、同じように実行することができるようだ。
(sourceコードを見たのだけれど仕組みがわからなったので、誤解しているかもしれない。)
(実験1と実験4)
今のところは、考察は以上。
環境
OS:FreeBSD 9.3-STABLE r268734以上