こんにちは、5日ぶり2度目のLIGアドベントカレンダー出場、まさくにです。おいおいお前ら12月が終わりゆくことが悲しいのは分かるけど、もっとアドベントカレンダー書いていけよ。(懇願)
さて、みなさん、 source
コマンド使っていますよね。
使い方はこんな感じ。
$ source ~/.zshrc
こいつ、ずっとドットファイルをリフレッシュするためのものかと思って脳死だったんですけれど、どうやら違うようだと思って調べた結果を書きます。
とりあえずマニュアル見る
$ man source
BUILTIN(1) BSD General Commands Manual BUILTIN(1)
NAME
builtin, !, %, ., :, @, {, }, alias, alloc, bg, bind, bindkey, break, breaksw, builtins, case, cd, chdir, command, complete, continue, default, dirs, do, done, echo, echotc, elif,
else, end, endif, endsw, esac, eval, exec, exit, export, false, fc, fg, filetest, fi, for, foreach, getopts, glob, goto, hash, hashstat, history, hup, if, jobid, jobs, kill, limit,
local, log, login, logout, ls-F, nice, nohup, notify, onintr, popd, printenv, pushd, pwd, read, readonly, rehash, repeat, return, sched, set, setenv, settc, setty, setvar, shift,
source, stop, suspend, switch, telltc, test, then, time, times, trap, true, type, ulimit, umask, unalias, uncomplete, unhash, unlimit, unset, unsetenv, until, wait, where, which,
while -- shell built-in commands
SYNOPSIS
builtin [-options] [args ...]
DESCRIPTION
Shell builtin commands are commands that can be executed within the running shell's process. Note that, in the case of csh(1) builtin commands, the command is executed in a subshell
if it occurs as any component of a pipeline except the last.
If a command specified to the shell contains a slash ``/'', the shell will not execute a builtin command, even if the last component of the specified command matches the name of a
builtin command. Thus, while specifying ``echo'' causes a builtin command to be executed under shells that support the echo builtin command, specifying ``/bin/echo'' or ``./echo''
does not.
While some builtin commands may exist in more than one shell, their operation may be different under each shell which supports them. Below is a table which lists shell builtin com-
mands, the standard shells that support them and whether they exist as standalone utilities.
Only builtin commands for the csh(1) and sh(1) shells are listed here. Consult a shell's manual page for details on the operation of its builtin commands. Beware that the sh(1)
manual page, at least, calls some of these commands ``built-in commands'' and some of them ``reserved words''. Users of other shells may need to consult an info(1) page or other
sources of documentation.
意訳
- sourceコマンドは実行中のシェルプロセスと同一プロセスでコマンドを実行する組み込みコマンド。
- sourceのオプションに
/
が含まれると、$PATH
が通っているコマンド(ファイル)より、指定された方を優先する。(逆にパラメタに/
が含まれなければ、$PATH
から一致するコマンド(ファイル)を探し出す)
というようなことが書かれていますね。どこにもリフレッシュするとは書かれていないし、2は知らなかった。コマンドを実行するコマンドなんですね。名前の意図が汲み取れない。なるほど、.zshrcを見る時、下記のようなことを書いていました。
$ source ~/.zshrc
つまりこれでできるのか。
$ PATH=~:$PATH && source .zshrc
まぁパス通してる分、長くなってるんですけど……。PATHが通ってればいいんですね。へー。
本当に同一プロセスで実行されているか
$ cat readable_script1.sh ## こんな感じのスクリプト書いとく
#!/bin/zsh
ME=$0
echo "## Start: "$ME
ps | grep -v iTerm2
echo "## END: "$ME
上記のようなスクリプト作って
$ source readable_script1.sh # sourceで実行
source readable_script1.sh
## Start: readable_script1.sh
PID TTY TIME CMD
61784 ttys001 0:03.16 -zsh # 今のzshだけが動いている
## END: readable_script1.sh
ちなみにこれをzshで動かすと以下のように
$ /bin/zsh ./readable_script1.sh # zshで実行しちゃうよ
## Start: ./readable_script1.sh
PID TTY TIME CMD
61784 ttys001 0:03.24 -zsh
71968 ttys001 0:00.01 /bin/zsh ./readable_script1.sh # 別のプロセスが立ち上がってる!
## END: ./readable_script1.sh
ので、 source
コマンドは同一プロセス内でコマンドを実行する、というのは分かりました。
.zshrcとかがリフレッシュされたように見えるのはなんで?
同一プロセス内で上書きされてるからなんですよね。きっと。
$ cat readable_script1.sh # こう書いて
#!/bin/zsh
ME=$0
echo "## Start: "$ME
LOVER=Emacs
echo "## END: "$ME
下記のように実行。
LOVER=Vim && source readable_script1.sh && echo $LOVER
## Start: readable_script1.sh
## END: readable_script1.sh
Emacs # VimがEmacsに変わっちゃったよ!
これがzshで実行されると
LOVER=Vim && /bin/zsh readable_script1.sh && echo $LOVER
## Start: readable_script1.sh
## END: readable_script1.sh
Vim # Vimのままだ!
っていうことなんで、各設定が上書きされるんですね。へー。そういうことだったのか。
sourceの中でsource呼ばれるとどうなるの?
気になりますね。
下記のようなスクリプト書いて
#!/bin/zsh
ME=$0
echo "## Start: "$ME
source readable_script2.sh
echo "## END: "$ME
#!/bin/zsh
ME=$0
echo "## Start: "$ME
LOVER=Emacs
echo "## END: "$ME
スクリプトの1つ目から2つ目をsourceで実行するようにしています。
で、これをsourceで実行すると
LOVER=Vim && source readable_script1.sh && echo $LOVER
## Start: readable_script1.sh
## Start: readable_script2.sh
## END: readable_script2.sh
## END: readable_script2.sh
Emacs # 上の上まで伝播する〜!というか同一空間内〜!
ということなんですね。へー。
おまけ1
.
はsourceコマンドとして動く。
LOVER=Vim && . ./readable_script1.sh && echo $LOVER
## Start: ./readable_script1.sh
## Start: readable_script2.sh
## END: readable_script2.sh
## END: readable_script2.sh
Emacs
おまけ2
.zshrc内でどうしてもそのマシン固有の変数とか、環境変数を入れときたいことありますよね。でも.zshrcで管理したくないですよね。僕はこうしています。
source $HOME/.env
これで $HOME/.env
に固有の設定を書いて、 .zshrc から切り離すことにしています。何かもっといい方法あんのかな。