2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Zshの謎コマンド「 - 」(ダッシュコマンド, ハイフンコマンド)

Last updated at Posted at 2024-12-14

簡単に言うと...

  • 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]の文字列の頭に-を付加した上で実行される」ようです...

はて、サッパリ意味がわかりません:thinking:

ググってみる

検索してみると、世界のどこかで私と同じく-コマンドに疑問を抱いた民が質問をしていました。

回答者たち曰く、どうやら-コマンドはZshだけでなく色々なシェルにもあるようです1
そして、一部のシェルは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]-を入れる & 環境変数ARGV0argv[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);

    ...
}

以上、めちゃめちゃニッチな豆知識でした

  1. 自分のMacに入っているシェル(bash,csh,dash,ksh,sh,tcsh,zsh)の中だとzshにしか入っていませんでした

2
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?