はうすてんぼぶ

コードかいてて疑問に思ったことや、興味あることをつらつらと暇なときに書く場所、ここはそんな場所

ファイルパーミッション

はじめに

ファイルのパーミッションはだいたい何なのかは知っているが、chmodコマンドぐらいしか満足に使い方をしらないので勉強するよ!

パーミッション

UNIXはファイルに対するアクセス許可状態を、オーナ、グループ、その他の3つの単位で設定することができる。

それぞれの単位ごとに、読み出し(read)、書き込み(write)、実行(executable)を可能/不可能にするファイル属性をパーミッションという。

最終的に一つのファイルのパーミッション設定は、rwxrwxrwxのように9文字で表され、左から3文字ずつオーナグループその他のアクセス許可状態を指している。

文字が書かれている場所は可能、「-」が置かれている場所は不可能を指す。

試しに作ってみた例を以下に示す。

% echo "Hello World" > file1
% ls -l file1
-rw-rw-r-- 1 bob bob 12  919 08:37 file1

左側にある「-rw-rw-r--」の箇所がパーミッションに当たる。
今回の場合だと、オーナは、「read/write」、グループは「read/write」、その他は「read」が許可されていることがわかる。

じゃあ一番左の「-」は何なのかというと、これはファイルの種類を指す。
全7種類ありみたいだけれども、上の3つぐらいしか見たことがない。

記号 種類
- 通常ファイル
d ディレクトリ(directory)
l シンボリックリンク(link)
b ブロックデバイス(block device)
c キャラクタデバイス(character device)
p パイプ(pipe)
s ソケット(socket)

/devになら揃ってそう、と思ってls -lしてみた結果を一部載せる。

% ls -l /dev/
brw-rw----+ 1 root cdrom    11,   0  918 03:16 sr0
crw-rw----  1 root video    29,   0  918 03:16 fb0
srw-rw-rw-  1 root root           0  918 03:16 log

sr0はCD/DVDドライブ、fb0はメインディスプレイを指す。
logは名前の通りログファイルなんだろうけどそもそも読むことができなかった。そもそもファイル状態がソケット…とは?

あとsr0のパーミッションの一番右に「+」が付いているが、これは拡張アクセス権限とのこと。
acl(アクセス制御リスト、Access Control Lists)と呼ばれる。
それまで所有者以外のアクセス設定はグループ単位 or 全員みたいに極端なことしかできなかったが、aclを扱うことで、ユーザを個別に設定してアクセス許可/不可の設定ができる、とのこと。
BK class: ls -lで表示されるモードの11桁目を参考にしました。

新規作成時のパーミッション値の設定:umask

umaskコマンドで、パーミッションマスク値の設定ができる。
このパーミッションマスク値を設定すると、新規にファイルやディレクトリを作った時のパーミッションに影響を与える。

とりあえず、一般ユーザとrootで試してみた。

% echo "test1" > file 
% ls -l file
-rw-rw-r-- 1 bob bob 5  919 09:14 file

% umask
002

% sudo -i
# cd /home/bob
# echo "test2" > root_file

# ls -l root_file
-rw-r--r-- 1 root    root    6  919 09:20 root_file

# umask
022

一般ユーザのときは002、スーパーユーザのときは022なことが分かった。

ファイルやディレクトリの新規作成時のパーミッション処理は、仮パーミッション値とマスクの否定値をアンド計算したものになる。
パーミッション値は、ファイルだと666、ディレクトリだと777になる。

上の例で、一般ユーザがファイルを作るときは、
110110110 & ~000000010、となり、

  110110110
&111111101
ーーーーーーー
110110100 > 664 > rw-rw-r-- となる。

umaskコマンドに新しいパーミッション値を引数として与えるとマスク値が変更される。

% echo "umask 002" > file_a
% umask 077
% echo "umask 077" > file_b
% ls -l file_a file_b
-rw-rw-r-- 1 bob bob 10  919 09:33 file_a
-rw------- 1 bob bob 10  919 09:33 file_b

今使っているシェル内でだけ変更は有効になるので、永続的に変更したいのであれば.zshrcなどのシェルの設定ファイルに書くと良いのかも。

パーミッションの変更:chmod

マスクは新規にファイルを作る時に用いられるが、既に作成済みのファイルのパーミッションを変更したい場合はchmodコマンドを使う。

chmodの主な使い方は2種類で、+-=でモードの追加・削除・設定をするモード文字での設定方法(設定モード)と、直接パーミッション値を8進数3桁で設定する方法(8進数モード)がある。

語源は、CHange MODより。

設定モード

まず例から、

% chmod [MODE] [FILE]
% chmod u+rwx file1 (1)
% chmod go-r file2 (2)
% chmod o=rw file3 (3)

それぞれのchmodとファイル名の間にある[MODE]の部分を変えて、パーミッションを変更する。

(1)の例を使うと、「u+rwx」の部分は、
どのユーザ」の「どの権限」を「どうするか」の3つを示している。
この例だと、オーナ読込・書込・実行権限追加する、といった意味になる。


どのユーザ」には、以下の4種類の英字が入る。

u オーナ
g グループ
o その他ユーザ
a 全ユーザ(省略可)

(2)の例のように、複数入れても問題ない。a+何かで、対象が重複して入れても問題ない(aが優先されるだけなので)。
また、省略した場合は、自動的に全ユーザが対象になる。


どうするかオペレータと呼ぶらしい)」は、以下の3種類の記号が入る。

+ モード追加
- モード削除
= モード設定

これは1つのみ設定可能。省略もしてはいけない。
あと、削除する場合に、対象のユーザがその権限を持っていなくても特にエラーはでない(設定に寄る?)。

どの権限モードと呼ぶらしい)」は、以下の5種類の英字を入れる。

r 読込
w 書込
x 実行
s SUIDビット・SGIDビット
t stickyビット

これも例(1)(3)のように一度に複数入れることが可能。
下の2つのsとtについては後述する。

パーミッション値を使う

パーミッション値を使うほうが自分はしっくりくる。
使い方はシンプルで以下のようになる。

% chmod [OCTAL_MODE] [FILE]
% chmod 664 file1 (a)
% chmod 700 file1 (b)
% chmod 777 file1 (c)

[OCATAL_MODE]の箇所に8進数の3桁の数値を入れるのみ。
3桁の数値に関しては、マスクのところでも触れたので割愛する。

例にだけ触れとくと、
(a)は、オーナとグループに読込・書込を許可し、その他のユーザに読込を許可。
(b)は、オーナにのみ読込・書込・実行を許可。他のユーザは読込すら許可しない。
(c)は、全ユーザに全権限を与える。

(a)(b)(c)の後にls -lしてみた結果を示す。

% chmod 664 file1
% ls -l file1
-rw-rw-r-- 1 bob bob 12  919 08:37 file1

% chmod 700 file1
% ls -l file1
-rwx------ 1 bob bob 12  919 08:37 file1

% chmod 777 file1
% ls -l file1
-rwxrwxrwx 1 bob bob 12  919 08:37 file1

ファイルモードを知る

chmodコマンドから急に、モードという単語が出てきた。

UNIXは、パーミッションを9ビット、さらに3つの属性を追加した12ビットセットをファイルモードとして管理している。
このファイルモードから来ている。

パーミッションの9ビットは言わずもがな、rwxrwxrwxの許可/不許可を指すそれである。

先に12ビットセットがどう並んでいるかだけ示す。

[SUID][SGID][stcky]rwxrwxrwx

パーミッション9ビットの前に3ビット分、SUID、SGID、sticky用のビットが付いている状態。
この3属性について説明していく。

SUID (Set User ID) ビット

一般ユーザがファイルを実行すると、普通はそのコマンドを入力したユーザIDが、プロセスのユーザIDになる。
SUIDビットを設定(1に)しておくと、誰が実行しようともファイル所有者(オーナ)のユーザIDが、そのプロセスの実行ユーザIDとみなされる。

こうしておくことで、「ファイル所有者が実行しないと正常に処理されない」ようなプログラムも、他のユーザが実行した場合でも正常に動かすことが可能になる、とのこと。

SGID (Set Group ID) ビット

このファイルのグループIDが、実行プロセスのグループIDになる。
いわゆるSUIDのグループ版。

stickyビット

この値が1になっていると(chmodで+t)されていると、ファイル所有者とスーパユーザだけが書き込み権限を持つようになる。
主にディレクトリに対してこの設定をするようで、/tmpディレクトリのように、多くのユーザに共有されるがディレクトリの削除は困る、といった場合に付けるらしい。

実行可能ファイルに対してstickyビットがセットされている場合には、実行終了後もメモリ開放しない(スワップ領域の保存)という扱いになるため、次回の起動が早くなるらしい。

ここらへんはもう少し触ってみないとわからなさそう。

自分の状況を把握:id, groups

パーミッションの設定をする際は、idコマンドやgroupsコマンドで自分の所属を知っておくことも重要。

groupsコマンドは、自分の所属するグループ名を一覧で表示。
idコマンドは、ユーザID,グループID,所属するグループIDを表示してくれる。

% groups
bob adm dialout cdrom plugdev lpadmin admin sambashare

% id
uid=1000(bob) gid=1000(bob) groups=1000(bob),4(adm),20(dialout),24(cdrom),46(plugdev),116(lpadmin),118(admin),124(sambashare)

あまり設定したつもりがなくても結構勝手にgroupに入っていたので驚いた。

おわりに

これでパーミッションに関する箇所は網羅したのではないかなぁ。
stickyビットがまだあいまいなので要復習。

参考資料

Amazon.co.jp: 改訂 新Linux/UNIX入門: 林 晴比古: 本, Chapter 9 ファイルのアクセス制御, p138-p148.

環境変数

環境変数の勉強をば。

自分は今現在PATHぐらいしか知らないし、おそらく過去にそれ以上の環境変数をいじった記憶は…無い。

せめて、どの項目が何を指しているのかぐらい覚えておきたいので、大事そうな奴だけここでまとめておく。

環境変数を見る方法

setprintenvで見ることができる。

ただし、setコマンドの場合は、シェル変数も含まれるので環境変数だけ見たい場合にはprintenvで見ることを推奨。

% printenv | sort
COLORTERM=gnome-terminal
COMPIZ_CONFIG_PROFILE=ubuntu
〜〜〜 省略 〜〜〜

順番を指定するオプションは無いので、行単位で出力してくれるsortコマンドにパイプで渡すと見やすくて良い。

特定の環境変数だけ見たい場合は、引数に指定すると見ることができる。

% printenv HOME USER
/home/bob
bob

またはechoコマンドを使っても見ることができる。
それぞれの環境変数は「$環境変数名」で参照できる。

% echo "HOME: $HOME\nUSER: $USER"
HOME: /home/bob
USER: bob

設定方法

exportコマンドは、シェル変数を環境変数に昇格させることができる。
シェル変数だけだと、子プロセスで値を参照することはできないが、
それを環境変数にすることで、そのシェルで実行される子プロセスは全てその変数を参照することが可能になる。

ちなみにシェルを閉じるとそのexportで設定した環境変数も破棄される。

設定してみた例を以下に示す。

% TEST=123
% echo $TEST
123

% zsh (新しくzshを起動)
% echo $TEST
()
%exit (子プロセスのzshを閉じる)

% export TEST
% printenv TEST
123

% zsh (新しくzshを起動)
% ecoh $TEST
123

環境変数の中身

じゃあ実際にそれぞれの環境変数が何を担っているのかを書いていく。

PATH

プログラムの置いてあるディレクトリ名の指定。

頭から順に該当するプログラムが置いてあるかどうか調べていくので、
もし同名のプログラムが複数ある場合には、その順序に気を付ける必要がある。
もしPATHの中で同名のプログラムが複数ある場合には、whereコマンドで調べることができる。

% where test
/usr/bin/test
/usr/local/bin/test

HOME

ホームディレクトリ。

シェルが起動したときのカレントディレクトリであり、
引数なしでcdしたときに移動するディレクトリ。

LANG

使用言語の指定。

C
ja
japanese
ja_JP.EUC
ja_JP.JIS
ja_JP.SJIS
ja_JP.PCK 

などがある。

自分のUbuntuの環境ではja_JP.UTF_8だった。

LANGUAGE

GNU独自の環境変数で、複数の言語を:で繋いで指定できる。

非標準のものらしく、「第一希望:第二希望」のように記述する。

% printenv LANGUAGE
ja:en

となっていたので、第一希望を日本語、第二希望を英語としている様子。

SHELL

現在使用しているシェルをフルパス表記したもの。

% printenv SHELL
/bin/zsh

PWD

カレントディレクトリ名

cdで移動するたびに書き換わる。

EDITOR

標準エディタの指定。

自分の環境で指定されてなかったのでvimを設定しておいた。

% export EDITOR=/usr/bin/vim

こうすると、それまでcrontab -eを実行ときはviがエディタとして起動していたが、vimで起動するようになった。
ただ、シェルを閉じるとこの環境変数も消えるので、.zshrcに書いておくことで対応した。

終わりに

とりあえず環境変数の見方、設定方法と、代表的な環境変数に付いて触れた。

自分の環境でprintenvで見る限り、まだまだ全然あるのが恐ろしい。

manコマンドのように環境変数のマニュアルというものを見ることはできないものか…。

参考資料

環境変数マニュアル, http://x68000.q-e-d.net/~68user/unix/environment.html.
さんすけ unix 参考書(UNIX その他/2 環境変数), http://www5b.biglobe.ne.jp/~sgi/unix/unixA/ux502.html.
IPA ISEC セキュア・プログラミング講座:C/C++言語編 第8章 入力検査:環境変数の検査とリセッ, http://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c703.html.

Unixシェルコマンドの勉強 part 3

はじめに

前々回前回に引き続きpart 3。

ひとまず今回で、基礎的なコマンド11個について勉強したことになる。

今回触れるのは、

cp, mv, cat, less

の4つ。

参考資料は、参考書「Amazon.co.jp: 改訂 新Linux/UNIX入門: 林 晴比古: 本」。

cp

概要

ファイルをコピーする。
語源はCoPyより。

使い方は以下の通り。

% cp [file1] [file2] (単体のファイルコピー)
% cp [files] [dir] (ファイル(複数可)をディレクトリへコピー)
% cp -r [dir1] [dir2] (ディレクトリをまるごとコピー)

単体のファイルをコピーする際は、[file1]にコピー元、[file2]にコピー先のファイル名を入れる。

ディレクトリへファイルをコピーする場合は、[files]にコピー元の単体(または複数)のファイル名、[dir]にコピー先のディレクトリ名を入れる。このコピー方法だと、自動的にコピー先のファイル名は、コピー元と同じになる。

ディレクトリをまるごとコピーする際は、[dir1]にコピー元のディレクトリ名、[dir2]にコピー先のディレクトリ名を入れる。

オプション

-p

ファイル属性を維持したままコピーしたい場合はこのオプションを用いる。

タイムスタンプやオーナ情報やグループ情報を維持したままコピーされる。

語源は、preserveより。

オーナ情報などはcpコマンドを読んだときのユーザの名前になるので、維持したい場合には-pが必要になる。

% sudo cp -p file file2
% sudo cp file1 file2
% ls -l
合計 12
-rw-rw-r-- 1 bob bob 5  917 23:08 file1
-rw-rw-r-- 1 bob bob 5  917 23:08 file2
-rw-r--r-- 1 root    root    5  917 23:38 file3

-pを付けないと、オーナ情報や権限情報が変わっていることがわかる。

-r

ディレクトリをコピーする際はこのオプションが必要になる。

語源は再帰を意味するrecursive。

コピー先のディレクトリがあるか無いかで動作が異なる点に注意。
以下に、コピー先のディレクトリがある場合と無い場合で実行した結果を載せる。

% ls
dir1 dir2

%ls dir2
()

% ls dir1
file1 file2

% cp dir1 dir2 (dir1ディレクトリを既存のdir2へコピー)
% ls dir2
dir1

% cp dir1 newdir (dir1ディレクトリを新しくnewdirとしてコピー)
% ls newdir
file1 file2

存在するディレクトリへコピーする場合には、コピー元のディレクトリが、存在するディレクトリのサブディレクトリとしてコピーされる。
存在しないディレクトリへコピーする場合は、コピー元のディレクトリを新しいディレクトリとしてまるごとコピーする。

mv

概要

ファイルの移動とファイル名を変更する。
語源は、MoVeより。

使い方は以下の通り。

% mv [files] [dir]
% mv [file1] [file2]

ファイルの移動をする場合には、最後にディレクトリ名を指定する。
以下のようにディレクトリ名の前に複数ファイルを指定しても良く。
シェルグロブを用いて、複数ファイルを指定しても良い。

% mv file1 file2 dir2
% mv file* dir2

また、ファイル名を変更する場合にもmvコマンドを使う。

オプション

参考書には主なオプションとして、-i-fが取り上げられている。-iは他のコマンドと同じく確認を表示し、-fも他のコマンドのオプションと同様に問答無用で(コピー先に同名のファイルがあろうとなかろうと)コピーする。

なのでここでは割愛する。

aliasにmv = 'mv -i'としておくとコピー先に同名のファイルがあっても安全なので、もし確認されず上書きされた場合には設定ファイルに書いておこう。

cat

概要

ファイルの内容を表示する。
語源は、conCATenate(連結させる)。

ファイル連結をさせるためのコマンドらしいが、基本的に単一ファイルの内容を表示させるために用いられる。

使い方は以下の通り。

% cat [file_1] [file_2] ...

[file_n]にファイル名を指定することで、その中身を見ることができる。
複数指定すると、連続してファイルの中身が出力される。

%cat -n file1 file2
     1	this is file1.
     2	this is file2.

注目して欲しいのは、オプションで-nで行番号を表示させる場合には、ファイルが異なっていても連番で出力される点である。語源のconcatenate(連結させる)はこういうところから来ていると思う。

オプション

-n

行番号を表示する。
複数のファイルを引数で与えた場合には、上の例のように、ファイルが異なっていても連番で行番号が振られる。

-b

空白の行に番号を振らずに、行番号を表示する。

% cat file3
()
this is file3.

% cat -b file1 file2 file3
     1	this is file1.
     2	this is file2.

     3	this is file3.

-nは空行にも行番号を振るため、
状況によって-nと使いわけると良い。

-v

非印字文字を特殊な形式で文字として表示する。

実行ファイルをcatでやると文字化けした感じで出力されるが、-vを付けると一応文字化けなしで見ることができる。

ただ、どっちにしろ読めたものではない。むしろ付けないほうが読みたいところを読める場合もある。

less

概要

テキストをページ単位で表示する。

同じくテキストをページ単位で表示するmoreの機能強化版で、「moreの反対」という遊び感覚で名前を付けられたのが語源?らしい。

% less [files]

といった感じに使う。

触ってみた感じ、manを実行したときと操作方法は同じだと思う。

% less file1 file2 file3
% less file*

のように複数指定することもできる。
次のファイルに行くときは:n(next)とすれば次のファイルを表示できる。
また:p(previous)で前のファイルを表示できる。

オプション

参考書に載っている主なオプションが多いので表形式で載せる。

-s 連続した空白行を1行に圧縮する
-c いったん画面クリアしながら次ページ表示をする
-E 最終行まで表示したら自動的に終了する
-e 最終行まで表示し、更に次に進むと終了する
-i 文字列検索の時大文字/小文字を同一視する
-m 全体の何%の部分を表示しているかガイド表示する
-M -mと同じだが詳細を表示する
-行数 1度にスクロールする行数を指定
+行番号 指定業から表示開始
+/文字列 指定した文字列のある行から表示開始。一致文字列が反転表示される。

おそらく普通にvimなどのテキストエディタとかで見たほうが良いとは思う。

終わりに

これでひとまず、基本的なコマンドの勉強に関してはひとまず終わり。

まだ全然触れていないコマンドはあるが、それらは触りつつ覚えていくっきゃない!!

Unixシェルコマンドの勉強 part 2

さて、二回目。

はじめに

前回からの続き。
今回は、

cd, mkdir, rmdir, cp

の4つ。

一回目と変わらず、参考資料は、Googleの検索結果と、昔買った参考書「Amazon.co.jp: 改訂 新Linux/UNIX入門: 林 晴比古: 本」。

cd

概要

カレントディレクトリを移動する。
Change working Directoryが語源。

以下のように使う。

% cd [dir_name]

[dir_name]を省略すると、ホームディレクトリに移動する。

参考書に書かれている便利な使い方を載せる。

% cd ..   (ひとつ上のディレクトリに移動する)
% cd ../dir_1 (ひとつ上のディレクトリにあるサブディレクトリに移動する)
% cd ~ (ホームディレクトリに戻る)
% cd (同上)
% cd ~- (直前のディレクトリに戻る)

オプション

cdコマンドはオプションを付けられない。
man cdってやってもマニュアルがでてこないのは、「おまえそれくらい知ってろよ」ってことなのだろうか。

mkdir

概要

ディレクトリを作成する。
語源は、MaKe DIRectories

以下のように使う。

% mkdir [dirctory_1] [directory_2] ... 

[dirctory_n]にディレクトリ名を入れる。
引数を追加することで、一度に複数のディレクトリを作ることができる。

オプション

参考書に書かれていた-pについてだけ言及する。

-p

mkdirの引数にディレクトリ名を入れれば、ディレクトリは作られるが、以下のように、サブディレクトリのサブディレクトリを作ることもできる。

% mkdir dir1/dir2
mkdir: ディレクトリ `dir1/dir2' を作成できません: そのようなファイルやディレクトリはありません

ただし、もしdir1が無いと、例のようにそんなディレクトリありません、みたいなエラーが出力される。

% mkdir dir1 dir1/dir2

としてもよいが、子の子の子とかの場合、とても手間。

こういうときは、-pオプションを付けることで、一番最後のサブディレクトリの親ディレクトリが無い場合は自動的に作ってくれる。

% mkdir -p dir1/dir2

語源は、parents。

rmdir

概要

空のディレクトリを削除する。
語源は、ReMove empty DIRectories。

使い方は、

% rmdir [directory_1] [directory_2] ...

のようになる。
使い方は、上のmkdirの逆バージョンと考えて問題ない。
空のディレクトリでないと削除できない点に注意。

オプション

mkdirと同じように-pオプションが使えるが、途中で空でないディレクトリがあると削除処理がそこで止まってしまうので、大分使い勝手は悪い。

ディレクトリをまるごと削除するときは、下に取り上げるrm -rを使う。

rm

概要

ファイルを削除する。
語源はReMove。

使い方は、以下の通り。

% rm [file_1] [file_2] ...

削除するファイル[file_n]は複数指定できる。

オプション

主なオプションは3つ。

-i

削除確認メッセージを表示する。書き込み禁止ファイル時の警告もする。

これを付けると、削除する際に、yes/noの確認がされる。

% rm file1
rm: 通常ファイル `file' を削除しますか? n

% ls
file1

% rm file1
rm: 通常ファイル `file' を削除しますか? y

%ls

確認に対する答えは「y」で始まっていればyesと答えたことになり、それ以外はnoとして処理される。

-f

書き込み禁止ファイルであっても警告を出さずに削除する。

恐ろしいオプション

下の-rオプションと/を組み合わせると一撃必殺される。

-r

指定ディレクトリを削除する。

rmdirの上位互換という扱いで問題無い。
指定したディレクトリ以下にあるファイルもディレクトリも全て削除される。

-irとすると鬱陶しいぐらい確認用のメッセージが表示され、-rfとすると無慈悲な削除が行われる起こるかもしれない。

おわりに

今回は、cdmkdirrmdirrmの4つのコマンドを取り上げた。

削除系のコマンドはとんでも無いことが起こりうるので寝ぼけているときとか意識が朦朧としている時にやってはいけない。

シェルスクリプトを書いてみよう 基礎編

あまりシェルスクリプトを書いたことが無かったので、基本的なとこを勉強しつつ触ってみる。

コマンドラインで書いていることを、スクリプトに書いておけば楽できる、みたいな感覚。

とりあえず、基礎的な部分として、書き方と実行方法、引数の渡し方、定期実行の方法あたりに今回は触れます。

とりあえず

zsh上で、ファイルにコマンドを書いて実行してみた。

% echo "echo \"Hello World\"" > shell_file
% zsh shell_file
Hello World

これだけだと寂しいので、実行するとホームディレクトリに飛んで、lsを実行してくれるようなものを書いてみた。

% cat gohome
cd ~/
pwd
ls

これを実行すると、ホームディレクトリの現在の場所が表示された後に、ファイル一覧が表示される。

が、その実行方法によってちょっと異なる点がある。

シェルスクリプトの実行方法には、以下の3つがある。

source [script_name]
. [script_name]
zsh [script_name]

上のsourceと.で実行する場合は、現在の環境でそのスクリプトを実行する。
zsh(環境によってはbashだったりする)で実行すると、新しいシェルが起動してそこでスクリプトが実行される。

新しいシェルを起動して実行した場合は以下のようになる。

% pwd
/home/bob/example

% zsh gohome
/home/bob
ダウンロード
テンプレート
〜〜〜 省略 〜〜〜

% pwd
/home/bob/example

現在の場所が変わっていないことが分かる。
これは、新しいシェルでカレントディレクトリは移動したが、元の環境でcdが実行されていないため。

sourceで実行した結果は以下のようになる。

% pwd
/home/bob/example

% zsh gohome
/home/bob
ダウンロード
テンプレート
〜〜〜 省略 〜〜〜

% pwd
/home/bob

現在のシェルで実行すると、cdによって現在場所も変わったことがわかる。

ファイルモードで実行を可能にする

シェルスクリプトを実行すうrときに、毎度毎度sourcezshと書くのは結構手間だったりする。
そういったときは、chmodを用いて、そのスクリプトファイルを「実行許可ファイル」に設定すれば、ファイル名だけでスマートに起動できる。

chmod +x [shell_script]
chmod u+x [shell_script]

これで、[shell_script]に、スクリプトファイルを指定すれば実行許可ファイルになる。「+x」だと全ユーザでそのファイルを実行可能になり、「u+x」だとユーザ本人だけが実行可能になる。

さっき書いたシェルスクリプトのgohomeファイルを使って、以下に例を書く。

% gohome
zsh: command not found: gohome

% chmod u+x gohome

% gohome
zsh: command not found: gohome

% ./gohome
/home/bob
ダウンロード
テンプレート
〜〜〜 省略 〜〜〜

% pwd
/home/bob/example

注意したいのが、実行許可ファイルにした場合は、新しいシェルが起動してそこでシェルスクリプトが実行されるということである。
上の例では、gohomeを実行許可ファイルにし実行してみたが、最後のpwdcdが適用されていないことがわかる。

起動シェルの指定

シェルスクリプトを実行許可ファイルにすると、一つ問題が発生する。
というのも、今の環境と同じシェルが起動して、そこでシェルスクリプトが実行されるので、もしそのシェルスクリプトが別のシェル環境用に書かれていた場合には動かない場合がでてくる。

なので、シェルスクリプトの一行目にシバン(shebang)を書いておくことで、スクリプトを読み込むインタプリタを指定することができる。
シバンは、#!で書き始める必要がある。

なのでさっき書いたgohome(本来の名前の役割はもう果たせないけれども…)も最初にzshで実行して欲しい!ってことをシバンで書いておく必要がある。

% cat gohome
#! /bin/zsh
cd ~/
pwd
ls

なぜ、パスを書かなきゃいけないかというと、別のシェル環境が/binをPATHに設定していない場合でも実行可能にするため、だと思う。

引数の渡し方

引数を渡す場合は、

% source [script_file] [arg0] [arg1] ...

のように、[arg0]、[arg1]のように半角スペースを開けて渡す。

スクリプト側で、その引数を参照するためには、以下の3つの方法がある

名前 説明
$@ 全引数
$* 全引数(環境変数IFSで示す文字で区切る)
$# 引数の数
${n} n番目の引数(0はコマンドラインの先頭名が入る)

n番目の引数を参照する際、nが一桁なら{}は不要。ただ、${2}のようにしても問題ないので、{}常時{}で囲む癖を付けといたほうが良いのかも。

以下のようなファイルを準備して実行してみた。

% cat argtest_file1
#! /bin/zsh
echo "0: ${0}"
echo "1: ${1}"
echo "2: ${2}"
echo "#: $#"
echo "@: $@"
echo "*: $*"

実行結果は以下の通り。

% ./arg_file hoge fuga
0: ./arg_file
1: hoge
2: fuga
#: 2
@: hoge fuga
*: hoge fuga

それ以外にも以下のような特殊変数がある。

名前 説明
$? 最後に実行したコマンドのexit値
$$ プロセスID
$! シェルが最後に起動したバックグラウンドプロセスのプロセスID
$- シェルの起動時のフラグ、setコマンドを使って設定したフラグの一覧

定期的に実行したい場合

作ったシェルスクリプトを定期的に実行したい場合はcrontabを使う。

crontabコマンドに入力すると、それが設定ファイルに書き込まれるので、

% echo "*/1 * * * * /home/bob/example/logDate" | crontab
% crontab -l
*/1 * * * * /home/bob/example/logDate

のようにすれば設定できる。
または、crontab -eでviを起動して直接記述しても良い。

設定書式は、以下のようになっている。

[minute] [hour] [date] [month] [day_of_week] [path]

[minute]: 分(0-59)
[hour]:時(0-23)
[date]:日(1-31)
[month]:月(1-12)
[day_of_week]:曜日(0-7)
[path]:実行したいコマンド(シェルスクリプトファイル)へのパス

設定した値になった際に、[path]のコマンドが実行される。
例えば、以下のようにすると毎時10分のときにhogeが実行される。

10 * * * * /home/bob/hoge

*は、そのフィールドで取りうるすべての値を表現する。
また、ダッシュやコンマを用いることで、範囲指定やリストを指定できる。

10,20,30 * * * * hoge (毎時10分、20分、30分のときに実行)
10-30 * * * * piyo (毎時10分〜30分の間は毎分実行)
5,10,20-30 * * * * fuga (毎時、5分と10分と20〜30分の間に実行)

間隔設定をしたい場合は/を使う。
15分ごとに実行したい場合は、

*/15 * * * hoge

とする。

以下のようなlogDateという現在時刻をファイルに追記する実行ファイルを作っておいて、crontabに登録した例を示す。

% cat logDate
#! /bin/zsh
date >> ~/log.txt

% echo "*/1 * * * * /home/bob/example/logDate" | crontab

〜 3分後 〜

% cat ~/log.txt
2012917日 月曜日 21:43:02 JST
2012917日 月曜日 21:44:02 JST
2012917日 月曜日 21:45:01 JST

crontab -rで、現在のcrontabを削除する(全ての設定を削除)。
個別に不要になったものを削除する場合には、crontab -eで編集モードで行ごと削除するようにしよう。

  • rのオプションは誤爆すると危険なので、シェルの設定ファイルに以下のaliasを追加しとておくと安心安全。
alias crontab='crontab -i'

こうすることで、crontabの削除が行われそうになっても確認がでるようになる。

終わりに

今回はシェルスクリプトの基礎的なとこを書いてみた。
追々もっと深くまで勉強する必要はあるが、とりあえずここまで。

参考資料

Amazon.co.jp: 改訂 新Linux/UNIX入門: 林 晴比古: 本, Chapter 26 シェルプログラミング.
引数処理 シェルスクリプトサンプル, http://www.unix-vm.com/command4_7.html.
UNIXの部屋 コマンド検索:crontab (*BSD/Linux), http://x68000.q-e-d.net/~68user/unix/pickup?crontab.
crontabの書き方 — server-memo.net, http://nweng.wiki.fc2.com/wiki/crontab%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9.

正規表現とか

パーサーを作る上で避けては通れない正規表現

「文法理解しとる?理解しとるかお前!」と聞かれたら「NO!!!」と力強く言えるので、勉強します。

でも、欲しいところを掠めとるだけなら(.*?)だけでいい気はするんだよね!

基本的にパターン文字列を作るときは、PHP正規表現チェッカーを使っています、はい。

文法の種類

使える文法の量は、基本 < POSIX < Perlで増えていく。

POSIX

POSIXは、POSIXクラスという文字区分を定義でき、例えば"[:upper:]"みたいに書くと"[A-Za-z]"と同じ意味を持つ。

便利といえば便利だが、POSIXクラスを使わずに普通に"[A-Z]"と書いた方が分かりやすかったりする。
"[:space:]"は"[ \t\n\r\f\v]"と同じ意味を持つので便利なのかも。あまり色々なスペースに対応しなきゃいけない正規表現を書いたことが無いのでわからないんだけども…。

どちらかといえば、拡張することで、"+"(1回以上の連続する文字)、"?"(0または1回だけの文字)、"|"(OR)の3つのメタ文字が使えるようになることのほうが利点が大きい。

Perl

POSIXもより豊富な文法を持つのがPerl
上で挙げた"[:upper:]"や"[:space:]"などのPOSIXクラスは使えなくなっている。その変わりに、"\d"や"\s"などのクラスが使えるようになっている。

また、".*?"で最短マッチができるようになったのも大きい。
"hogefuga"から、それぞれタグで囲まれた箇所だけを抽出したい場合は、"(.*?)"とするだけで良いから楽チン。

文法

Amazon.co.jp: 改訂 新Linux/UNIX入門: 林 晴比古: 本によると、
以下の6種類が基本的な正規表現記号(メタ文字)として取り上げられているので、それをば。

記号 説明
^ より外なら行先頭。内なら否定
$ 行の末尾
. 任意の一文字
* 直前の文字の0回以上の繰り返し
[] []内の任意の1文字
/ メタ文字のエスケープ

これ以上のメタ文字を使う場合は、だいたいそれはPOSIXかPerlで拡張する必要があるものだと考えて良い、はず。
実際6つだけで事足りることも多いが、Perlに慣れてしまうと、「くっそ!"?"使えないとか詰んでるし!」となる。

文字クラス

"[ ]"は文字クラスとも呼ばれ、"[abc]"とすると「aかbかcのどれか一文字」にマッチする。"[a-z]"という書き方をすると「a,b,c,...,x,y,zのどれか一文字」にマッチする。

"[ ]"の中でしか使えない文法もあるので以下にまとめておく。

記号 説明
- 範囲
^ 先頭に置くと「以外にマッチ」
a-z 小文字の半角英文字
A-Z 大文字の半角英文字
0-9 数字

下3つは定型句みたいな感じの書き方だけども覚えておいて損は無い。
あと、"[A-Za-z]"で半角英数字にマッチになる。

"-"の範囲は文字コードに依存の順番に寄る点に注意。
Unicode対応 文字コード表を見てみるとわかるけれども、UTF-8だとAは41、Zは5A、aは61、zは7Aになっている。
なので、A-zは良くても、a-Zはエラーが返る。
あとZとaの間に"\]^_'"の記号が含まれているので"[A-z]"は『半角英文字』を意味せず、『一部記号と半角英文字』を意味するよくわからん感じになるので、半角英数字をマッチさせたい場合はちゃんと"[a-zA-Z]"としましょう。

実際に使ってみる

対象とするfileには、以下のような文字列が書かれているとする。

% cat file
abcde
a0b1c2d3
bob tom jon
abc123
123abc

それをgrepを用いて行検索をしてみる。

% grep "a" file
abcde
a0b1c2d3
abc123
123abc

% grep "^a" file
abcde
a0b1c2d3
abc123

% grep "$3" file
a0b1c2d3
abc123

% grep "^[a-z]" file
abcde
a0b1c2d3
bob tom jon
abc123

% grep "c[0-9]" file
a0b1c2d3
abc123

% grep "a*d" file
abcde
a0b1c2d3

% grep "a.b" file
a0b1c2d3

文字列置換をする場合には、sedperlを使う。
perlを使うと、Perlの正規表現が使えて便利。

% cat bfile
boom bomb bob

% sed "s/b.*?b/---/g" < bfile
boom bomb bob

% perl -pe 's/b.*?b/---/g' < bfile
---om---ob

()で囲むと後方参照ができる(sedは基本となる正規表現の文法しか使えないので\(\)で囲む必要がある)。
()で囲んだ箇所を\1、\2、…とすることで後方参照できる。

% perl -pe 's/(bo)/\1ooo/g' < bfile
booooom boooomb boooob

おわりに

正規表現に関してまとめ、使ってみた。
行検索する場合のgrep、文字列置換を行いたい場合のsedやperlで正規表現の出番はあるため、しっかりみにつけておく必要があるな、と感じた。

パターン文字列を作るときは、試行錯誤的になりがちなので、正規表現を簡単にチェックしてくれるようなサービスを使えば、捗ると思うよ!

参考資料

Amazon.co.jp: 改訂 新Linux/UNIX入門: 林 晴比古: 本, p130-p135.
UNIXの部屋 コマンド検索: sed, http://x68000.q-e-d.net/~68user/unix/pickup?sed.
Linuxコマンド集 - 【 grep 】 文字列を検索する:ITpro, http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230786/.

標準ストリーム

今回はUNIXの標準ストリームに関して。

C++でHTTPサーバ作る際に、半強制的に入力とパイプを触らざるを得なかったので、少し知ってる、ってレベル。

C++でいう、

std::cout << "Hello Out-World." << endl; //出力
std:string str = NULL;
std::cin >> str; //入力

は、この標準ストリームと関係あるんだよね。

なんか普通に使っている気もするけど、すごく曖昧な感じなので、実際にコマンド打ちながら勉強してみますよ。

標準入出力

ざっくばらんな概要

早速、echoを使って例を交える。

% echo 'Hello World'
Hello World

この2行目のHello Worldが表示されるまでの一連の流れは、
標準入力(stdin)にキーボードで入力されたHello Worldが投げられて、
標準出力(stdout)で、そのHello Worldをディスプレイへ出力する、となる。

もう一個、エラー出力用の標準エラー出力(stderr)というのがあって、
この3つが標準ストリームと呼ばれる。

標準入力はキーボード、標準出力と標準エラー出力はディスプレイが対応付けられているので、
上のechoに関しても、特に出力先を指定しなかったので勝手にディスプレイに表示された、ってことになる。

このstdin、stdout、stderrはなんだかよくわからん存在なんだけれども、
その3つはファイルディスクリプタで、プロセス起動時に勝手に割り当てられる。

ファイルディスクリプタ

ファイルディスクリプタとは、ファイルの識別子
この識別子ってのが全然ピンとこなくてイマイチ理解できてない感はある。

ファイルを開いた時に勝手に割り当てられる番地で、
この番地に対してデータを投げることを入力、
その番地から返って来るデータが出力、だと俺は思っている。

「データが返って来る」って言うと勝手に戻ってくるみたいだけれども、
こちら側で、ファイルディスクリプタを使って向こうにデータを投げるのと同じで、
向こうのプロセス(stdoutだとOS?)も、こっちの入出力用のファイルディスクリプタを使って結果を投げているので、
第三者から見ると2つのプロセスが入力をしあっているように見えるのだろうか。

ユーザの視点からだと、

10: [キーボード] ---(入力)---> 0: stdin
20: [画面] <---(出力)--- 1: stdout

だが、OSから見ると、

0: stdin <---(出力)--- 10: [キーボード]
1: stdout ---(入力)---> 20: [画面]

こういうこと?よくわからぬ。

リダイレクト

上で、stdinとstdoutはそれぞれキーボードとディスプレイに対応付けられている、と書いた。
この標準入出力先を切り替えることを、リダイレクトするという。

たとえば出力先をファイルにすると、以下のようにlsコマンドの結果をファイルに入れることができる。

% ls > ls_result.txt
% cat ls_result.text
ダウンロード
テンプレート
〜 省略 〜

入力先をファイルに置き換えることもできる。

% echo 'Hello Bob' > file1.txt
% tr "Bob" "Tom" < file1.txt > file2.txt
% echo file2.txt
Hello Tom

tr [set1] [set2]を普通に使うと、

% tr "Bob" "Tom"
Hello Bob (キーボードからの入力)
Hello Tom

こんな感じになるが、「<」と「>」を使うことで、簡単にfile1.txt中の文字列を置き換えた結果をfile2.txtに入れることができる。

リダイレクト記号

>や<はリダイレクト記号といって、これを使って、入出力先を切り替えたりする。
そんなに数が多くないので、参考書を元に表でまとめておく。

記号 説明
標準入力をファイルにする
> 標準出力をファイルにする
>> 標準出力をファイルに追加する
>& エラー情報もファイルに出力する
>>& エラー情報をファイルに追加する
2> エラー情報だけファイルに出力する

>と<はさっき使ったので、>&と>>&の例を取り上げる。

% cat err.txt
エラー出力を書き込むためのファイルです
% tr hoge >& err.txt
% cat err.txt
tr: `hoge' の後にオペランドがありません
% tr fuga >>& err.txt
tr: `hoge' の後にオペランドがありません
tr: `fuga' の後にオペランドがありません

上の例では最初の、

% tr hoge >& err.txt

でerr.txtに出力したため、ファイルにもともと書いてあった内容は消えてエラー内容だけが書きこまれた。
次の、

% tr fuga >>& err.txt

でerr.txtに追加出力したので、一度目のエラー内容の後に、新しいエラー内容が書きこまれているのが分かる。

- : 標準入力を指定する

「-」は標準入力を明示的に指定する際に使われる。省略すると標準入力になるが、場合に寄っては明示しないと困るときもある。
stdinの代名詞見たいな感じに使う。

以下のように、ファイルの先頭に追記したい際は、catの第一引数に標準入力を指す「-」を入れればおっけー。

% cat - err.txt > file3.txt
# エラー出力結果
% cat file3.txt
# エラー出力結果
tr: `hoge' の後にオペランドがありません
tr: `fuga' の後にオペランドがありません

これはcatコマンドの機能ではなく、シェルの機能である、という点に注意。

set -o noclobber: リダイレクトを抑止する

リダイレクトは便利だけれども、出力先が既存ファイルだと一気に危険性が増す。

% echo ';)' > 卒論.txt

ってうっかりやっただけで卒論を無力化できるのだから何それ恐い。

こういう恐ろしいことを防ぐためには、
set -o noclobberを使って前もってリダイレクト書き込み禁止にしておくと良いみたい。
再度、リダイレクト書き込みを許可する場合には、set +o noclobberを実行するだけ。

% set -o noclobber
% echo ';)' > 卒論.txt
zsh: ファイルが存在します: 卒論.txt
% set +o noclobber
% echo ';)' > 卒論.txt
% cat 卒論.txt
;)

これ.zshrcに書いておいたほうが安全なのでは!?

パイプ

パイプ(|)を使うと、コマンドライン上だと「コマンドの出力を、別のコマンドの入力に流す」ことができる。
それまで、一度ファイルに出力していたようなものも、パイプを利用すると簡単にかけるので便利。

% ls | wc -l
33

これは、lsで出力した結果の行数をwcで出力しているってだけ。

もしパイプを使わないと。

% ls > tmp.txt
% wc -l < tmp.txt
% rm tmp.txt

のように、一時的にファイルを作らないとできない。

つまりパイプを使うと、それまで出力先がディスプレイかファイルに限定されていた文字列を、別のコマンドの入力として流すことができる、ってことになる。

リダイレクトは、文字列がダバダバ流れるパイプがそれまで画面に繋がっていたものを切り替えて、別のファイルに繋げるもの。

% echo "Hello World" ------ X [画面] Hello World
                                       '---- 0 [ファイル] file.txt

パイプは、文字列がダバダバ流れるパイプを別のコマンドに流すのだからイメージとしては、

% echo "Hello World" ---
% cat                            ---'

みたいな感じになる。

おわりに

標準ストリームに関してはだいたいこんな感じ。

リダイレクトはコマンドの出力をファイル書きだすときに使うし、パイプはコマンド間で連携をするときに使うし、
これはもっと早く勉強しておくべきだった。

あと、grepとパイプはえらく相性が良いというか、やたらと何かとセットで出てくるわけがわかった。
grepで見つけたファイルの中身をさらに検索しにいったり正規表現で置換する、とかはパイプを使えば一行で済む!!良い!

どこか間違っているとこがあったらご指摘お願いします。

参考資料

Amazon.co.jp: 改訂 新Linux/UNIX入門: 林 晴比古: 本, Chapter19 リダイレクト操作(p258-p-265), Chapter 20 パイプとフィルタ(p268-p270).
標準入力、標準出力、標準エラー出力、パイプとは ?, http://www.creatology.jp/unix/outin.html.
UNIXの標準入出力とリダイレクション, http://www.rsch.tuis.ac.jp/~ohmi/literacy/stdio.html.
標準入出力使用のすすめ, http://www-or.amp.i.kyoto-u.ac.jp/algo-eng/db/stdinout.html.
パイプによるプロセス間通信 [Linux] - Web/DB プログラミング徹底解説, http://keicode.com/note/lin07.php.

FHS 〜置くべき場所に置け〜

はじめに

つまり、Filesystem Hierarchy Standard←これ読もう、ということ。

Ubuntuを触っていると、binやdevとかのディレクトリに図らずもいかねばならんときがある。
でもそもそも、binとかdevとか何々です?と疑問に思いつつも今までPATHを.zshrcに追記してたりしてた。

そんな悩みを解決してくれるのが、FHS(Filesystem Hierarchy Standard)。
これにはディレクトリの用途に関してや、どんなファイルをどのディレクトリに置くべきか、などが書いてある。

が、長いし英語だし死ねるので参考書やFHSに載ってる重要なものについてだけガーっと触れる。

FHS?

Wikipediaさんより

Filesystem Hierarchy Standard(FHS、ファイルシステム階層標準)は、Linuxと他のUNIXオペレーティングシステムでの主なディレクトリとその内容を定めたものである。大部分において、BSD系のディレクトリ階層を基にして拡張し定式化している。

つまるところ、「お前らUNIXを使うからにはこれに則ってディレクトリ構造作れよ?絶対だぞ?」といった感じ。
これが定められる前は、はびこるUnix系OSと独自構造で阿鼻叫喚だった様子。

現行標準となっているのは2004年にリリースされた2.3だが、どうもFHS 3.0 Draft 1 | The Linux Foundationによると今年の7月1日に3.0としてドラフト版がリリースされている。

構造

といっても、基本的にうまくまとめられている様子なので、3つの資料を元にそれぞれに書いてあるものをまんま引用して表形式で並べます。

エンタープライズ: - 第14回:FHSによるディレクトリの規格化』からの引用は引用符(FHSの和訳っぽい様子で、一番しっかり書いてあるため)

Filesystem Hierarchy Standard - Wikipedia』からの引用は頭にW:
参考書の『Amazon.co.jp: 改訂 新Linux/UNIX入門: 林 晴比古: 本』からの引用は頭に参:

/bin

 /binディレクトリは,「システム管理者やユーザーが利用し,且つ起動時やメンテナンス時に必須のコマンド類」を格納するために利用される。シェルやファイルの属性変更,ファイルのコピーや削除といった代表的なコマンドは,この/binディレクトリに配置する。

W:シングルユーザモード(英語版)で必要となる一般ユーザー向けの基本コマンドの実行ファイル (binaries)。例えばcat、ls、cpなど。
参:バイナリ形式の実行可能ファイル。UNIXの基本コマンドがここに置かれる(ls, cp, mvなど)

/boot

 /bootディレクトリには,「起動時に必要なカーネルイメージやブートローダー」ファイルなどが配置されている。

 カーネルのイメージ(vmlinuz)は,ルートディレクトリ(/)またはこの/bootディレクトリのいずれかに配置されていなければならない。

W:ブートローダー (boot loader) 関連のファイル群。例えば、カーネルや initrd(初期RAMディスク)。通常は別パーティション。
参:Linuxカーネルやブート処理に必要なファイルが置かれる。

/dev

 /devディレクトリには,デバイスファイルが配置されている。/dev/cdromなどが該当する。

W:基本デバイス(device)。例えば、/dev/nullなど。
参:デバイスファイルが置かれる

/etc

 /etcディレクトリには、このシステムの環境設定ファイルを配置する。

 システム管理者は,/etcディレクトリ内のファイルを編集することでシステムの環境設定を行う。FHSでは,システム設定に必要なファイル群は,この/etcディレクトリ下にまとめて配置するように構成されている。このため/etcディレクトリ以外に格納されているファイルを編集する必要がないよう配慮されている。

W:システム全体に関わる固有設定ファイル群。
参:システム管理用の各種設定ファイルと起動時に実行されるスクリプトが置かれる。

/etc/X11

 X Window Systemの設定ファイルを保存するためのディレクトリ。Xconfig, XF86Config, Xmodmapなどのファイルが含まれる。

W:X Window System, version 11 用の設定ファイル群。

/home

 /homeディレクトリは必須ではない。このため,用意されていても,いなくてもよいのだ。

 一般に/homeディレクトリには,各ユーザーがファイルを保存できるようにユーザー名と同名のディレクトリをそのユーザーが所有するように作成し,その下を各ユーザーが自由に読み書きできるように設定する。

W:ユーザーの ホームディレクトリ (home directory) 群。セーブファイル、個人用設定など。別パーティションとすることが多い。
参:ユーザのホームディレクトリが置かれる。

/lib

 /libディレクトリには,/binディレクトリや/sbinディレクトリに置かれたコマンドの実行に必要となる共有ライブラリファイルを配置する。

 /libディレクトリの内容は,OSをインストールする際に標準で用意される。システム管理者は,/libディレクトリに後からインストールする共有ライブラリを保存すべきではない。さもないとOSのアップグレード時やパッチ適用時に上書きされる可能性があるためだ。

 また,起動や/bin,/sbinディレクトリ内のコマンドの実行に必須とされない共有ライブラリは,この/libディレクトリではなく,後述の/usr/libディレクトリに保存する。

W:/bin/ や /sbin/ にある実行ファイルの基本となるライブラリ (library) 群。
参:共有ライブラリ(C言語のライブラリなど)が置かれる。

/mnt

 /mntディレクトリは,一時的にマウントする場所として利用する。例えば,フロッピーディスクやCD-ROMのマウント先として利用するのだ。このディレクトリ下にはどのような実ファイルも存在しない。

W:ファイルシステムの一時マウントポイント (mount)
参:CD-ROMやFDの一時的なマウント用ディレクトリ。実体は空のディレクトリ。/mnt/cdromや/mnt/floppyなどがある。

/media(補足)

FHSの2.3より追加された、CD-ROMなどのリームバブル媒体(media)のマウントポイントはこちらになった様子。

/opt

 /optディレクトリ下は,付加的なアプリケーションのインストール先に使われる。

 /optディレクトリにはパッケージ名のサブディレクトリを作り,その下に個々のアプリケーションのプログラムをインストールする。

W:オプション (option) のアプリケーションソフトウェアパッケージのインストール用

/proc

W:カーネルやプロセス (process) の状態に関する情報を主にテキストで示す仮想ファイルシステム(例えば、実行時間やネットワークなど) 用。procfsのマウントポイント。
参:Linuxカーネルの動作情報を含む特殊なファイルシステム

/root

 /rootディレクトリは,rootユーザーのホームディレクトリだ。この位置が必須ではないが,/rootディレクトリをrootユーザーのホームディレクトリとして用意しておくことが推奨されている。ランレベル1で動作する際を考えれば,home/ディレクトリ下にroot/が含まれない理由も自ずとから分かってくるだろう。

W:rootユーザのホームディレクトリ。
参:スーパーユーザのホームディレクトリ

/sbin

 /sbinディレクトリには,システム管理者が用いるコマンド群が配置されている。

 システム管理者が用いるコマンドを格納するディレクトリは,この/sbin以外にも,後述する/usr/sbin,/usr/local/sbinの2つのディレクトリがある。

 /sbinディレクトリには,起動時やメンテナンス時に必要とされるコマンド類を格納し,起動やメンテナンスに必須とされないコマンドについては,/usr/sbinディレクトリに格納する。

W:システム管理系コマンドの実行ファイル群(例えば、init、ip、mount)。(system binaries)
参:システム管理者が使用する実行可能ファイルが置かれる。shutdown、mountなど緊急時に必須のコマンドが置かれる。

/tmp

 /tmpディレクトリは,一時的に利用するテンポラリファイルを格納するのに用いられる。

 /tmpディレクトリに保存したファイルやディレクトリは,システムの起動時にすべて削除される。

W:一時ファイル置場 (temporary files)。/var/tmp も参照されたい。リブート時に内容が保持されない。
参:一時的なファイルの置き場として使用される。

/usr

 /usrディレクトリは,システムの起動時には必要がないファイルを配置するためのものだ。

 /usrディレクトリ内のファイルは,システムによって書き換えられることはない不変のデータとして構成される。そのため,/usrディレクトリ以下をNFSなどを使ってネットワークで他のコンピュータと共有して利用したり,読み取り専用でマウントしたりしても,問題なく動作することが保証される。

W:ユーザーが共有する読み込み専用データの第二階層。大部分の(マルチ)ユーザ・ユーティリティとアプリケーションを格納する[26] (User Services and Routines)。
参:起動には必要ないが重要なプログラムが置かれる。

/usr/bin

 /usr/binディレクトリには,一般ユーザーが用い,且つ起動時に必要がないコマンド群を配置する。次のファイルが存在するかどうかは任意である。

W:一般ユーザ向けだが基本的ではないコマンドの実行ファイル(シングルユーザモードで必要としない)。
参:UNIXの一般コマンド

/usr/include

 /usr/includeディレクトリには,一般的なインクルードファイルが格納される。ここのインクルードファイルは,OSのインストール時に用意されるものだ。システム管理者が後からインクルードファイルをインストールする場合には,後述の/usr/local/includeにインストールする。

W:標準 includeファイル群
参:C言語のヘッダファイル

/user/games

 OSで標準に提供されるゲームのバイナリファイルが格納される。システム管理者が後からインストールするゲームは,後述の/usr/local/gamesディレクトリにインストールしよう。

参:ひと休み用

/usr/lib

 このディレクトリには,/usr/binや/usr/sbinディレクトリに格納したバイナリを動作させるために必要な共有ライブラリファイルがインストールされる。システム管理者が後から独自の共有ライブラリファイルをインストールしたい場合には,後述の/usr/local/libディレクトリにインストールする必要がある。

W:/usr/bin/ や /usr/sbin/ にある実行ファイルの基本となるライブラリ (library) 群。

/usr/local

 /usr/localディレクトリは,システム管理者がインストールする各種ファイルを保存するディレクトリだ。

 このディレクトリ内に格納したファイルは,完全にシステム管理者に開放されている。OSのシステムインストール直後は,ディレクトリ階層だけが用意されていて中身は空になっている状態だ。

 システム管理者が何らかのアプリケーションをインストールしたいのであれば,この/usr/localディレクトリ下か,前述した/optディレクトリ下にインストールしよう。

W:ホスト固有のローカル (local) データを格納する第三階層。通常、さらにサブディレクトリとして bin/、lib/、share/ などを持つ

/usr/share

 アーキテクチャに依存しないファイル群,例えばオンラインマニュアルなどが含まれる。

W:アーキテクチャに依存しない共有 (shared) データ
参:UNIXのマニュアルなど

/var

 /varディレクトリは,動的に変化するファイルを格納する。例えば,キャッシュデータやシステムログ,プロセスIDのファイルなどが動的に変化するファイルに相当する。また,Red Hat Linux 7.2などでは,Apacheで公開するドキュメントなどもこのディレクトリ下に設定されている。

 /varディレクトリには書き換えられるファイルが含まれるため,読み書きできるようにマウントしなければならない。またファイルサイズも大幅に増減することが考えられるため,/varディレクトリには十分な空き容量が確保されている必要がある。

W:可変 (Variable) なファイル群。内容が常に変化するようなファイル群を格納する。例えば、ログ、スプール、一時的電子メールファイルなど。別パーティションとすることもある。

おわりに

というか、これは読んで理解するというより、実際にcdで行ってlsしてみんとよくわからん!

参考資料

Amazon.co.jp: 改訂 新Linux/UNIX入門: 林 晴比古: 本, p188-p189.
Filesystem Hierarchy Standard - Wikipedia, http://ja.wikipedia.org/wiki/Filesystem_Hierarchy_Standard.
エンタープライズ: - 第14回:FHSによるディレクトリの規格化, http://www.itmedia.co.jp/help/howto/linux/0007master/14/.