Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

チルダ(~)はどうしてホームディレクトリになるのか

たまに忘れてコケたり,周りでも困っている人がいるようだったのでメモ.

追記(2020-09-06T11:25+09:00)

この記事では仕組みのほうについて記述しており,由来については書いてなかったのですが,ブコメでホームディレクトリがチルダで表記されるようになった由来について幾人かの識者にご指摘いただきました.

unix.stackexchange.com

ちょうどHOMEキーと同じ場所にチルダキーがあったんですね.ありがとうございました.

tl;dr

  • ~/$HOME/と同義である
  • ~/$HOME/に,ひいては実際の$HOME/の中身に展開されるのはシェル(e.g. bash, zsh, etc...)の拡張機能
  • シェルを使わなければその機能は使えないので,手で展開する必要がある
  • シェルを使わない状況: プログラム中からパスをいじるような場合,DockerfileのCMDなど

~---- ホームディレクトリに展開される便利な文字

チルダはホームディレクトリを表します,というのはLinux初心者が真っ先に習う内容で,ホームディレクトリに便利にアクセスすることができる.*NIX系のOSを使っている人はほぼ毎日のように使っているのではないだろうか.

ちなみに~foobar/と書くとユーザfoobarのホームディレクトリになることはあまり知られていない.

その他の用法は例えばbashのマニュアルに書いてある.

www.gnu.org

どこで展開されるの

チルダはホームディレクトリだよん,ということは大抵の人は知っているのだが,どうしてですかと言われると知らないということもありそう.実際自分もよく知らなかったので調べることになった.

チルダが$HOMEに展開されるのは,シェルがそれを展開しているからである.

これは一体何を意味しているのか?そう,シェルを介していない場合はチルダはホームディレクトリを指し示さないということである.

チルダが使えない場合

シェルを介さない場合の例について考えてみよう.

例えばプログラミング言語からホームディレクトリにある実行ファイルを呼び出したいとする.

// ビルドして~/bin/okに保存する
fn main() {
    println!("ok");
}

上掲のソースコードをビルドして~/bin/okに配置し,rubyで以下を実行する:

exec "~/bin/ok"

するとokと表示される.しかしながら以下のパターンでは失敗する:

exec ["~/bin/ok"]

なぜ失敗するかというと,前者のパターンではシェルを経由して(おそらく/bin/sh -c の引数として)~/bin/okを実行しようとする(具体的な条件は言語による.rubyの場合はメタ文字がある場合である)のに対し,後者ではシェルを経由せず,直接システムコールを使って~/bin/okを呼び出そうとする.シェルによる展開が行われないから,後者は実行ファイルを見付けられずに失敗する.

Traceback (most recent call last):
        1: from -:1:in `<main>'
-:1:in `exec': wrong first argument (ArgumentError)

同じような例はDockerfileでも起こる.CMDには2通りの書き方がある:

# Pattern A
CMD "foobar arg1 arg2"
# Pattern B
CMD [ "foobar", "arg1", "arg2" ]

ご賢察の通り,前者はシェルを経由するが後者では経由しない.

シェルを経由するかしないかはだいたいその言語のマニュアルに書いてあるので,読むとよさそう.もしくは,そのコマンドが動作中にpstreeなとのユーティリティでプロセスツリーを眺めると様子が分かって便利.シェルを経由しているとsh -cが間にはさまっている.

おわり

プログラムから他プログラムを呼び出す,といった場合,プログラム上でなにがしかの呼び出しを行う→(シェルの起動)→OSによるプロセスの立ち上げ,の順で話が進むので,プロセスまわりを押さえておくと良さそう. そして,OSはプロセス立ち上げに際して,$~の展開は行わない,それはシェルの仕事だと覚えておくと良さそう.

あとはこれ読んでください

tatsu-zine.com

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?