シェルの環境

INPUT · スライド

コマンドが見つかる仕組み(`PATH`)

01 / 06

ls はどこにいるのか

ずっと ls と打ってきたけれど、ls はどこにあるんだろう。

~ $ which ls/bin/ls

/bin/ls というただのファイルだよ。章9の地図の回で見た /bin だね。

つまりあなたが打っていたのは、これの短い書き方だったんだ。

~ $ /bin/ls        こう打っても同じ

では、なぜ ls だけで済むんだろう。答えは前の回の変数だよ。

~ $ echo $PATH/bin:/sbin:/usr/bin:/usr/sbin

これがコマンドを探す場所のリストだよ。: で区切って4つ並んでいるね。

1. /bin       を見る2. /sbin      を見る3. /usr/bin   を見る4. /usr/sbin  を見る

ls と打つと、シェルはこの4つを順に見に行って、最初に見つかったものを実行するんだ。

魔法ではなかったでしょう。変数に書かれた場所を、上から順に探しているだけだよ。

02 / 06

command not found の正体

この仕組みが分かると、いちばんよく出るエラーの意味も分かるよ。

~ $ aisatsu-sh: aisatsu: not found

これは「そんなコマンドは存在しない」ではないんだ。正しくはこうだよ。

> PATH に並んだ場所を全部見たけれど、aisatsu という名前のファイルは無かった

だから原因は2つに絞れるよ。

1. 本当に入っていない       →  入れる2. 入っているが PATH に無い →  PATH に足す or フルパスで打つ

2つめが意外と多いんだ。特に自分で作った道具や、/opt などの変わった場所に入れたソフトだね。

終了ステータスも決まっているよ。

~ $ aisatsu~ $ echo $?127

前の回で見た 127 だね。127 は「コマンドが見つからない」専用の番号だよ。

これを知っていると、スクリプトの中で見分けられるようになるんだ。

1    コマンドは動いたが失敗した127  コマンド自体が無かった

原因がまったく違うので、分かれているのはありがたいことだね。

03 / 06

自分の道具箱を作る

自分で作ったスクリプトも、名前だけで呼べるようにできるよ。

~ $ mkdir bin~ $ echo '#!/bin/sh' > bin/aisatsu~ $ echo 'echo ohayou' >> bin/aisatsu~ $ chmod +x bin/aisatsu~ $ aisatsu-sh: aisatsu: not found     ← まだ呼べない

実行の印は付けたのに、まだ見つけてもらえないね。PATH に入っていないからだよ。

足すとこうなるよ。

~ $ PATH=$PATH:$HOME/bin~ $ aisatsuohayou

動いたね。書き方をよく見てね。

PATH=$PATH:$HOME/bin     ↑     ↑  いまの中身  そこに足す場所

いまの中身を壊さずに、後ろに足しているんだ。前の回の「変数を変数に入れる」形だよ。

これを忘れるとひどいことになるよ。

PATH=$HOME/bin      ← いまの中身を捨ててしまった!

こう打つと lscat も動かなくなるんだ。慌てず export PATH=/bin:/sbin:/usr/bin:/usr/sbin と打ち直せば戻るけれど、$PATH: を付ける癖を最初から付けておこう。

04 / 06

順番が勝ち負けを決める

同じ名前の道具が2か所にあったら、どうなると思う?

~ $ PATH=$HOME/bin2:$PATH     前に足した~ $ aisatsubin2 no hou

PATH の前にあるほうが勝つんだ。順に探して、最初に見つかったところで止まるからね。

PATH=/home/manabiya/bin2:/bin:/sbin:...           ↑ ここで見つかったら、もう先は見ない

だから足す位置に意味があるんだよ。

書き方意味
PATH=$PATH:新しい場所後ろに足す(既にあるものを優先)
PATH=新しい場所:$PATH前に足す(新しいほうを優先

新しい版のソフトを入れたのに古い版が動く、というときはこれが原因だよ。

which そのコマンド    →  どちらが動いているか分かる

whichまさに PATH を順に探して、最初に見つけたものを答えるコマンドなんだ。あなたが手でやることを代わりにやってくれているだけだよ。

そして安全の話もひとつ。PATH の先頭に .(いまいる場所)を入れてはいけないよ。悪意のある ls を置いた場所に cd したら、それが動いてしまうからね。

05 / 06

シェルに組みこまれたもの

PATH を探さないコマンドもあるよ。

~ $ type cdcd is a shell builtin~ $ type lsls is /bin/ls

cdシェル自身に組みこまれているんだ。ファイルとして存在しないんだよ。

which cd    →  何も出ない(ファイルが無い)type cd     →  builtin と教えてくれる

なぜ cd は組みこみでないといけないか、分かるかな。

cd が別のプログラムだとすると  → 子のプロセスとして起動する  → その子の中で移動する  → 子が終わる  → 親(あなたのシェル)は動いていない!

前の回でやった「子で作った変数は親に残らない」と同じ話だよ。自分の場所を変えるには、自分でやるしかないんだ。

組みこみのものには他にこんなものがあるよ。

cd  export  unset  echo  read  set  exit  .  eval

echo は組みこみでもあり、/bin/echo としても存在する変わり者だよ。

道具の正体を調べる3つを並べておくね。

打つもの分かること
which 名前PATH の中の居場所
type 名前組みこみか、ファイルか
command -v 名前type に近い(スクリプト向き)

06 / 06

さあ、打ってみよう

この回で使う形をまとめておくね。

echo $PATH                     探す場所の一覧を見るtr ':' '\n' < 書き出したもの      1行ずつに分けて読むwhich ls                       居場所を調べるtype cd                        組みこみかどうか調べるPATH=$PATH:$HOME/bin           後ろに足すPATH=$HOME/bin:$PATH           前に足す(優先する)./tool.sh                      PATH を通さずに直接呼ぶ$HOME/bin/tool.sh              フルパスで呼ぶ

: で区切られた PATH は、読みにくいでしょう。章5の tr で1行ずつにすると読みやすいよ。

~ $ echo $PATH | tr ':' '\n'/bin/sbin/usr/bin/usr/sbin

知っている道具で、新しいものを読みやすくする。もう何度もやってきた手だね。

この回で作る自作コマンドは、章6と章11にもつながるよ。

章6   chmod +x で実行の印を付ける章10  PATH に置いて名前で呼ぶ章11  中身をちゃんと書く

今日は「名前で呼べるようにする」ところだけやろう。中身は1行で構わないよ。では打ってみよう。