Help us understand the problem. What is going on with this article?

sourceコマンドが.**rcをリフレッシュするコマンドじゃないと知る

こんにちは、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.

意訳

  1. sourceコマンドは実行中のシェルプロセスと同一プロセスでコマンドを実行する組み込みコマンド。
  2. 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呼ばれるとどうなるの?

気になりますね。
下記のようなスクリプト書いて

readable_script1.sh
#!/bin/zsh

ME=$0
echo "## Start: "$ME

source readable_script2.sh

echo "## END: "$ME
readable_script2.sh
#!/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で管理したくないですよね。僕はこうしています。

.zshrc
source $HOME/.env

これで $HOME/.env に固有の設定を書いて、 .zshrc から切り離すことにしています。何かもっといい方法あんのかな。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした