Just do IT

思うは招く

Linuxの「パスを通す」とは何か

プログラミングの学習を進めるにつれて、Linux特有の「パスを通す」の意味をしっかり理解しないと、環境構築で詰むケースが増えた。 よって、あらためて「パスを通す」の意味を整理した。

環境

なぜ wget コマンドは wget と打つだけで実行されるのか?

wgetとは、引数にURLを指定することでファイルをダウンロードできるコマンドのこと。普段は意識せずwget URLと打つだけで実行できるが、これは厳密に言うと以下のことをしている。

/usr/bin/wget URL

ただ、こんなコマンドをいちいち覚えていられない。だから「ある方法」を使ってwgetと叩くだけで/usr/bin/wget URLと同様のことを実現している。その方法が、この記事で解説する「パスを通す」という方法です。

では、なぜwgetコマンドを叩くだけでいいのか?理由は、「パスの通ったディレクトリ」に実行ファイルが保存されているから。パスの通ったディレクトリに保存されている実行ファイルは、./などと文頭につけなくても、wgetだけで実行できるようになる。

たとえば、Linux/usr/binディレクトリには、Linuxで使えるwgetコマンドの実行可能ファイルが入っている。(Linuxディストリビューションによっては違う名前のディレクトリかも)

binというのはbinaryを意味し、機械語という意味だ。/usr/bin/に入っている実行可能ファイルは、すべてパスを指定しなくてもファイル名で実行できる。いわば、特殊な権利を与えられた、特別なディレクトリということになる。

以下は、wgetコマンドと同じ働きをする。

# これでも動く
/usr/bin/wget URL

# いつもの
wget URL

繰り返すが、wgetコマンドがパスを指定しなくても動く理由は、/usr/bin/というディレクトリにパスが通っているから。

パスが通ったディレクトリを見る方法

では、どうやってその「パスが通ったディレクトリ」を知ればいいのか?

次のコマンドで確認できる。

echo $PATH

$PATHという変数の中に、パスが通ったディレクトリの情報が記されている。それをechoコマンドでコマンドラインに出力している。

結果

/home/vagrant/.yarn/bin:/home/vagrant/.config/yarn/global/node_modules/.bin:/home/vagrant/.yarn/bin:/home/vagrant/.config/yarn/global/node_modules/.bin:/home/vagrant/.yarn/bin:/home/vagrant/.config/yarn/global/node_modules/.bin:/home/vagrant/.yarn/bin:/home/vagrant/.config/yarn/global/node_modules/.bin:/home/vagrant/.yarn/bin:/home/vagrant/.config/yarn/global/node_modules/.bin:/home/vagrant/.nvm/versions/node/v10.14.2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:~/mybin

このように、パスが通ったディレクトリはひとつではなく、たくさんあって、:で区切られる。

ただ、これでは見づらいので見やすく出力する。

echo $PATH | sed -e 's/:/\n/g'
/home/vagrant/.yarn/bin
/home/vagrant/.config/yarn/global/node_modules/.bin
/home/vagrant/.yarn/bin
/home/vagrant/.config/yarn/global/node_modules/.bin
/home/vagrant/.yarn/bin
/home/vagrant/.config/yarn/global/node_modules/.bin
/home/vagrant/.yarn/bin
/home/vagrant/.config/yarn/global/node_modules/.bin
/home/vagrant/.yarn/bin
/home/vagrant/.config/yarn/global/node_modules/.bin
/home/vagrant/.nvm/versions/node/v10.14.2/bin
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
~/mybin

これらのディレクトリに、それぞれパスが通っている。ここに記載のあるディレクトリに実行可能ファイルを置くと、絶対パスを指定せずとも、ファイル名だけで実行が可能になる。

ためしに、/usr/bin/を見てみると、たくさんの実行可能ファイルが保存されていることが確認できる。

ls /usr/bin/
NF                                   gpic                               python3-jsondiff
 VGAuthService                        gprof                              python3-jsonpatch
'['                                   gresource                          python3-jsonpointer
 aa-enabled                           groff                              python3-jsonschema
 aa-exec                              grog                               python3.6
 acpi_listen                          grops                              python3.6m
 add-apt-repository                   grotty                             python3m
 addpart                              groups                             ranlib
 addr2line                            growpart                           rcp
 apport-bug                           grub-editenv                       rdma
~~~
# たくさんあるので省略

なお、もし同じ名前の実行可能ファイルがあった場合は、echo $PATHの出力結果の、左側のディレクトリに置いてあるものが優先される。

また、自分が新しく作成した実行可能ファイルを、既存のパスが通っているディレクトリに置くのはNG。 なぜなら、他の実行可能ファイルと混ざってしまい、自分のファイルがどれで、元からあったプログラムがなんなのかわからなくなるため。

新しく自分でディレクトリを作成し、そのディレクトリのパスを通してあげることで使用したほうがいい。

ディレクトリにパスを通す方法

試しに、こんなことをしてみる。

  • 自分で作ったプログラムファイルを作成
  • ディレクトリを作成
  • プログラムファイルをそのディレクトリに移動
  • そのディレクトリにパスを通す
  • プログラムファイルを実行

ここからの流れは以下のサイトを参考にさせていただく。

75.C言語で初めてのプログラミング

c言語のファイルを作成。

vim moji.c

以下を追記。

#include <stdio.h>

void main()
{
    printf("あなたご飯にする?");
    printf("お風呂にする?\n");
    printf("それとも、タ・ワ・シ?");
}

vim:wqで上書き保存。

gccコマンドでC言語コンパイル

gcc moji.c -o moji

実行してみる。

./moji

すると、

./moji
あなたご飯にする?お風呂にする?
それとも、タ・ワ・シ?vagrant@ubuntu-bionic:~$ 

改行がおかしいが、とりあえずコマンドは実行される。

次に、mybinというディレクトリを作成。

mkdir ~/mybin

~/でホームディレクトリに作成している。

さきほど作った実行可能ファイルをこのディレクトリにコピー。

cp moji ~/mybin/.

そしてついに、このディレクトリにパスを通す!

export PATH="$PATH:~/mybin"

exportコマンドを使っている。 これで、PATH変数の中身を書き換えて、自分が作ったディレクトリをPATH変数の中に追加した。

さらに詳しくいうと、"$PATH:~/mybin"$PATHには、以前まで設定されていたPATHが書かれているため、:で区切り、新しくパスを通したいディレクトリを登録している。

より具体的にすると、もともとPATH変数に保存されていた情報

/home/vagrant/.yarn/bin:/home/vagrant/.config/yarn/global/node_modules/.bin:/home/vagrant/.yarn/bin:/home/vagrant/.config/yarn/global/node_modules/.bin:/home/vagrant/.yarn/bin:/home/vagrant/.config/yarn/global/node_modules/.bin:/home/vagrant/.yarn/bin:/home/vagrant/.config/yarn/global/node_modules/.bin:/home/vagrant/.yarn/bin:/home/vagrant/.config/yarn/global/node_modules/.bin:/home/vagrant/.nvm/versions/node/v10.14.2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

この末尾に、:~/mybinを追記している。

参考: 80.環境変数の話

次に、$PATHを確認してみる。

echo $PATH | sed -e 's/:/\n/g'

すると、下のほうに登録されているのがわかる。

~ 省略 ~
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
# あった!
~/mybin

これで、ファイル名だけで実行されるか確認する。

moji
あなたご飯にする?お風呂にする?
それとも、タ・ワ・シ?vagrant@ubuntu-bionic:~$ 

どのディレクトリにいても、ファイル名だけで実行できるようになった。

永続的に値を設定したい場合

上記の設定方法だと、CUI環境を一旦終わらせると、変数の情報が元に戻る。

ためしに、vagrantを一旦終わらせて再度ログインし、mojiとコマンドを打ってみる。

moji
=> Command 'moji' not found

実行できなかった。

永続化するには、ホームディレクトリにある.bashsrcもしくは.bash_profileディレクトリのパスを通す設定を書く。

vim .bash_profile

でファイルを開き、

# テスト
export PATH="$PATH:~/mybin"

と書く。 そしてsourceコマンドで設定を再読み込みする。

source ~/.bash_profile

そしてmojiコマンドを打ってみると

moji
あなたご飯にする?お風呂にする?
それとも、タ・ワ・シ?vagrant@ubuntu-bionic:~$ 

実行された!

なぜこれができるかというと、Linuxでは、シェル(ここではbash)の起動時に~/.bash_profileを設定ファイルとして読み込むため。

参照