簡単に言うと...
- Zshには
-
というコマンドがある -
-
コマンドは、一般的なコマンドの前に記述することができるprecommand modifierの一種 (イメージ :% - cd
,% - ls
) -
zsh
コマンドの前に-
を書いて実行すると、起動するZ shellはログインシェルとなる
-
コマンドの存在に気が付いたきっかけ
きっかけは% cd -
について遊んでいたときでした。
シェルをいじる中で間違えて-
単体でエンターしてしまったのですが、よく見たらなんと正常終了していました。
% -
%
!?!?
慌てて% which -
してみますが...何も出てこない。
いや、オプションとして認識されてるのか!
# `--`で引数がオプションでないことを指定
% which -- -
-: shell built-in command
なんと-
(ハイフン)というコマンドがあるようです!
公式ドキュメント
-
コマンドはどんな機能なのでしょうか?
まずはZshの公式ページを見てみましょう。
6.2 Precommand Modifiers
A simple command may be preceded by a precommand modifier, which will alter how the command is interpreted. These modifiers are shell builtin commands with the exception of nocorrect which is a reserved word.
-
The command is executed with a-
prepended to its argv[0] string....
公式曰く、-
コマンドはPrecommand Modifiers(コマンド前修飾子)の一種で、「-
コマンドの後ろに渡されたコマンドは、argv[0]
の文字列の頭に-
を付加した上で実行される」ようです...
はて、サッパリ意味がわかりません
ググってみる
検索してみると、世界のどこかで私と同じく-
コマンドに疑問を抱いた民が質問をしていました。
回答者たち曰く、どうやら1。-
コマンドはZshだけでなく色々なシェルにもあるようです
そして、一部のシェルはargv[0]
をチェックし、先頭に-
がある場合は「ログイン シェル」モードになるそうです。
% cat > .bash_login
echo this is a login shell
% bash
bash$ exit
% - bash
this is a login shell
bash$
Some shells check their argv[0], and if there's a leading dash there, they go into "login shell" mode.
自分のZshにおいても.zlogin
ファイルを使って検証してみました。確かに-
コマンドにzsh
コマンドを渡すと、ログインシェルが立ち上がりました。また、環境変数ARGV0
に-zsh
を入れても同様の挙動をしました。
% cat > .zlogin
echo "this is a login shell"
% zsh
zsh$ exit
% - zsh
this is a login shell
zsh$ exit
% ARGV0='-zsh' zsh
this is a login shell
zsh$ exit
ただ、これは古い慣習の一つであり、現代において具体的な実用例はないようです。
ソースコードを見てみる
Zshのソースコードはgithubにて公開されています。コードを探索したところ、今回の話題に該当していそうな部分が見つかりました。
-
-
コマンドがargv[0]
に-
を入れる & 環境変数ARGV0
をargv[0]
にする様子 in exec.c
static void
execute(LinkList args, int flags, int defpath)
{
...
/* If ARGV0 is in the commands environment, we use *
* that as argv[0] for this external command */
if (unset(RESTRICTED) && (z = zgetenv("ARGV0"))) {
setdata(firstnode(args), (void *) ztrdup(z));
/*
* Note we don't do anything with the parameter structure
* for ARGV0: that's OK since we're about to exec or exit
* on failure.
*/
#ifdef USE_SET_UNSET_ENV
unsetenv("ARGV0");
#else
delenvvalue(z - 6);
#endif
} else if (flags & BINF_DASH) {
/* Else if the pre-command `-' was given, we add `-' *
* to the front of argv[0] for this command. */
sprintf(buf2, "-%s", arg0);
setdata(firstnode(args), (void *) ztrdup(buf2));
}
...
}
-
zsh
が立ち上がるときにargv[0]
をチェックし、ログインシェルにする様子 in init.c
static void
parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr,
int *needkeymap)
{
...
if (**argv == '-')
flags |= PARSEARGS_LOGIN;
...
}
...
static void parseopts_setemulate(char *nam, int flags)
{
emulate(nam, 1, &emulation, opts); /* initialises most options */
opts[LOGINSHELL] = ((flags & PARSEARGS_LOGIN) != 0);
...
}
以上、めちゃめちゃニッチな豆知識でした
-
自分のMacに入っているシェル(bash,csh,dash,ksh,sh,tcsh,zsh)の中だとzshにしか入っていませんでした ↩