UNIXコマンドマニュアル

a2p awk スクリプトを perl スクリプトに変換する

% a2p sample.awk > sample.pl
⇒ sample.awk (awkスクリプト) を sample.pl (perlスクリプト) に変換する。
FreeBSD では /usr/bin/a2p が perl4 用、package の perl5 に含まれる /usr/local/bin/a2p が perl5 用。
>> コマンド awk *   perl *

a2ps テキストファイルを Postscript に変換する

Postscript とはプリンタ用の言語である。
% a2ps file.txt | lpr -P printername (BSD 系)
% a2ps file.txt | lp -d printername (SystemV 系)
などと、Postscript データを lpr・lp コマンドで印刷できる。
>> コマンド dvi2ps *   gs *   ghostview *

ac ログイン時間の記録を表示

ユーザ別のログイン時間の記録を表示する。
% ac
total 42.99
これは、ac を実行したユーザは 42.99 時間ログインしていた、ということ。ただし、/var/log/wtmp の内容を元に時間を計算するので、/var/log/wtmp をクリアしてしまうとログイン時間が0に戻ってしまう。-p オプションを使うと、毎日の使用時間を表示できる。
% ac -p
Dec 17 total 2.15
Dec 18 total 6.47
Dec 19 total 2.54
Dec 20 total 3.36
Dec 21 total 10.26
Dec 22 total 4.20

コマンド名が似ているが、accton とは直接は関係ない。
>> コマンド accton *   lastcomm *   sa *

accton アカウント情報ログファイル作成の許可/禁止

普通のUNIXは、デフォルトではアカウント情報ログファイルは記録されないので、ログを取りたい場合は明示的に指定しなければならない。

一般的にログファイルは /var/account/acct である。/var/account/acct が存在しなかったら、まず
# touch /var/account/acct
でファイルを作成し、その後
# accton /var/account/acct
とすると、それ以降に実行されたコマンド名がログに記録される。この記録は sa コマンドや lastcomm コマンドで見ることができる。ログ作成を停止したい場合は、引数を与えず
# accton
とする。FreeBSDでは /etc/rc.conf でログ作成のオン/オフを指定できる。
>> コマンド ac *   lastcomm *   sa *

adduser 新規ユーザを追加する (FreeBSD)

68user というユーザを新しく登録する場合の例を以下に示す。
# adduser
Username: 68user
⇒ ユーザ名は「68user」
Full name: 68user
⇒ Full name も「68user」。会社や学校などなら「Yamada Taro」などとすればよい。
Uid (Leave empty for default): 2000
⇒ UID は 2000。
Login group [68user]: users
⇒ 68user が属するグループは「users」(既に存在している users というグループに属する)
Login group is users. Invite 68user into other groups? []: wheel
⇒ 他のグループにも属するか? と聞かれているので、su で root になるため wheel グループにも属するよう設定する。
Login class [default]: default
⇒ Login class は default のまま。
Shell (sh csh tcsh nologin) [sh]: tcsh
⇒ ログインシェルを指定。この場合は sh・csh・tcsh・nologin から選べ、と言っている。nologin とは /nonexistent のことで、両方とも実質的に telnet などでログインできないことを表す。ログインシェルの選択肢は、/etc/shells の内容によって変わる。ここではログインシェルとして tcsh を選択。
Home directory [/home/68user]: /home/68user
⇒ ホームディレクトリはデフォルトの /home/68user
Use password-based authentication? [yes]: yes
⇒ パスワードによる認証を使用する
Use an empty password? (yes/no) [no]: no
⇒ 空のパスワードは使わない
Use a random password? (yes/no) [no]: no
⇒ ランダムに自動生成したパスワードを使用する場合は yes
Enter password:
⇒ パスワードを入力。エコーバックはされないことに注意。
Enter password again:
⇒ 再度パスワードを入力。エコーバックはされないことに注意。
Lock out the account after creation? [no]: no
⇒ 作成したアカウントを凍結しておくなら yes
Username : 68user
Password : *****
Full Name : 68user
Uid : 2000
Class :
Groups : users wheel
Home : /home/68user
Shell : /bin/tcsh
Locked : no
OK? (yes/no): yes
⇒ 確認のため、入力した情報が表示される。これでよいなら yes とする。
adduser: INFO: Successfully added (68user) to the user database.
⇒ /etc/passwd・/etc/master.passwd・/etc/group に反映された。
Add another user? (yes/no): no
⇒ 引き続き他のユーザを追加するか? ここでは no として終了する。
Goodbye!

adduser を使わず、/etc/master.passwd を直接編集して、pwd_mkdb コマンドを実行する手もある(普通は素直に adduser を使うが)。つまり adduser コマンドは、自動的に /etc/master.passwd を編集し、pwd_mkdb コマンドを実行するプログラムなのである。

FreeBSD でのアカウント追加は adduser だが、Linux・Solaris・NetBSD では useradd コマンドを使う。
>> コマンド rmuser *   chsh *   vipw *   pwd_mkdb *   useradd *
>> 設定ファイル /etc/master.passwd *   /etc/passwd *   /etc/group *

afterstep NEXTSTEP 風のウィンドウマネージャ

かっちょいい外見と柔軟なカスタマイズ機能が人気がある。確かに見栄えはよいが色数をかなり喰うので、X が 8bpp (最大256色) だとかなり苦しい。この場合、減色したアイコン
を使うとよい。

AfterStep はユーザ固有の設定ファイルとして ~/.steprc を読み込む。それが存在しない場合は/usr/X11R6/lib/X11/afterstep/system.steprc がシステムデフォルトの設定ファイルとして利用される。ホームディレクトリに ~/.steprc が存在しない場合は、まず
% cp /usr/X11R6/lib/X11/afterstep/system.steprc ~/.steprc
% chmod +w ~/.steprc
としてシステム付属の設定をコピーし、その後 ~/.steprc を好きなようにいじればよい。

また、ウィンドウマネージャを (twm や fvwm から) afterstep に変えるには、~/.xsession (あるいは ~/.xinitrc) の最後に exec afterstep と書けばよい。afterstep-1.0 の設定方法は fvwm 系とほぼ共通だったが、afterstep-1.4 以降はかなり変わってしまった。

ちなみに、当ページ管理人は、afterstep-1.0 を国際化した afterstep-1.0-i18n を使用している。FreeBSD では
% env LANG=ja_JP.EUC afterstep &
とすると、タイトルバーやメニューに日本語が表示できる。
>> コマンド twm *   fvwm *
>> 設定ファイル ~/.xinitrc *   ~/.xsession *

agrep 曖昧検索を行う grep

grep・egrep・fgrep は指定したパターンに厳密にマッチする行を選び出すが、agrep は曖昧検索を行い、似ている行を選び出すことができる。

「似ているかどうか」は agrep のオプションで、いくつまでのエラーの数を許容するかで指定する。
% cat file.txt
hoga
hoge
moge
fuga
% agrep -1 hoge file.txt
hoga
hoge
⇒ エラーを 1 つまで許容する
% agrep -2 hoge file.txt
hoga
hoge
moge
⇒ エラーを 2 つまで許容する
% agrep hoge file.txt
hoge
⇒ 許容するエラー数を指定しない場合は、通常の grep と同じ動作をする。

-B オプションを指定すると、ひとつずつ許容するエラー数をあげていき、マッチした段階で動作を止める
% agrep -B hogo file.txt
best match has 1 error, there are 2 matches, output them? (y/n) y
hoga
hoge
⇒ 許容エラー数 0 でマッチしなかったため、許容エラー数を 1 にあげて再検索したところ、2 つマッチした

なお、grep・egrep・fgrep は UNIX 伝統のコマンドであるが、agrep は新参者で、メンテナンスされておらず、OS 標準コマンドではない。そういう意味では agrep は grep ファミリーの仲間とは言えない。
>> コマンド grep *   egrep *   fgrep *   zgrep *

alias コマンドの別名 (エイリアス) を設定する。シェルの内部コマンド。

あるコマンドを別のコマンド名で登録することで、長いコマンド名の短縮形を作ることができる。

csh・tcsh の場合は
% alias ls "ls -lFA"
% alias du "du -k"
% alias memo "mule ~/lib/memo"
% alias f "find / -name '\!*' -print"
などとする。一方、sh・bash の場合は
% alias ls="ls -lFA"
と「=」で結ばなくてはならない。

csh・tcsh・sh・bash とも、コマンドの前に `\' を付けることで、一時的にエイリアスを解除できる。
% alias "ls ls -lFA"
% ls (ls -lFA と同じ)
% \ls (alias が無効。普通の ls と同じ)
% ls (ls -lFA と同じ)

エイリアスを解除するには unalias を使う。alias コマンドを引数なしで実行すると、現在設定されているエイリアスの一覧を表示する。

普通 alias の設定は、~/.cshrc や ~/.profile などに記述しておく。こうすることで、ログインすると自動的に alias が有効になる。
>> コマンド unalias *

amp MPEG AUDIO Layer3 (MP3) プレイヤー

-q メッセージを表示しない
>> コマンド mpg123 *   sox *   splay *   xaudio *

apache 高機能WWWサーバ

シェア、信頼性、知名度など、総合的に見て一番よいと思われる WWW サーバ。CGI、SSI はもちろん、モジュールを組み込むことで色々な機能を使うことができる。
>> コマンド wwwstat *

appres Xのリソースの設定を表示

例えば kterm に関する現在のリソース設定の一覧を表示するには
% appres KTerm
とする。
>> コマンド listres *

apropos キーワードにマッチしたオンラインマニュアルを表示

あるキーワード、例えば「file」について記述してあるマニュアルの一覧が欲しい場合は
% apropos file
とする。これは
% man -k file
と同じ。

apropos・whatis とも、検索対象となるのは各マニュアルの「NAME」の項目だけで、マニュアルを全文検索してくれるわけではない。例えば ls コマンドのマニュアルは
NAME: ls - list directory contents
となっているので、ls コマンドを検索するには「list」「directory」「contents」のいずれかをキーワードに指定しなくてはならない。

apropos は指定の文字列が一部にマッチしていれば表示する。つまり、
% apropos dir
ls(1) - list directory contents
と、「dir」は「directory」にマッチするが、whatis は完全にマッチしないと表示されない。つまり
% whatis dir
では、ls コマンドは表示されない。
>> コマンド man *   whatis *

ar アーカイバ

ファイルをまとめて保管しておくためのユーティリティ。目的としては tar と同じだが、一般ユーザが使うことはあまりない。例えば、/usr/lib/lib*.a などのライブラリは ar でアーカイブされている。

-t オプションを指定すると、アーカイブされているファイルの一覧を表示する。
% ar -t /usr/lib/libc.a
__.SYMDEF
i386_set_ldt.o
i386_get_ldt.o
xdr_stdio.o
xdr_float.o
svc_tcp.o
svc_simple.o
svc_run.o
svc_raw.o
rpc_commondata.o
pmap_rmt.o
(略)
>> コマンド ld *   cc *

archie コマンドラインで FTP サイトから検索する。

archieについての詳しい説明は xarchie へ。
>> コマンド xarchie *

arithmetic 簡単な算数の問題を出題する

-o +-x/ 足し算、引き算、かけ算、割り算を出題する。引き算とかけ算のみをやりたかったら -o -x とする。

as アセンブラ

C をコンパイルする場合は、cc が自動的に as を呼んでくれる。
>> コマンド gas *   gcc *

astrolog 占星術のプログラムらしい

at 実行時間を指定してコマンドを実行

% at 10am -f foo.sh
⇒ 午前10時にシェルスクリプト foo.sh を実行
% echo ls | at 4pm + 2 days
⇒ 2日後の午後4時に ls を実行
>> コマンド crontab *   atq *   sleep *

atq at で指定されたコマンドのリストを表示

>> コマンド at *

awk テキスト整形ツール(パイプ)

一昔前は、perl のようにテキスト処理ツールとして広く使われてきた。

例えば
% ls -l | awk '{print $5,$9}'
とすることで、ファイルサイズとファイル名の一覧が得られる。この例は、入力を空白で区切り、5番目と9番目の列を出力している。空白以外を区切りとしたければ、-F オプションを使えばよい。例えば `.' を区切り (フィールドセパレータという) としたければ
% ls -l | awk -F . '{print $1}'
とする。

{} の前に任意の正規表現を書くと、そこにマッチした行に対して {} 内が実行される。
% ls -l | awk '/abc/ {print $5,$9}'
は、abc を含むファイル名と、そのファイルサイズを表示する。

特殊なパターンとして BEGIN と END がある。BEGIN は最初に実行され、END は最後に実行される。
% ls -l | awk 'BEGIN { print "START!"} {total+=$5; print $9} END {print "size total="total} '
これは、BEGIN {…} で最初に START! と表示し、各行ごとにファイルサイズを変数 total に加算し、END {…} を使って最後にファイルサイズの合計を表示するものである。

スクリプトとして動作させるには、-f オプションを付けて
#!/usr/bin/awk -f
BEGIN { print "START!"}
{total+=$5; print $9}
END {print "size total="total}
などと書く。

awk は一冊の本が書けるほど高機能なので、ここではこれ以上は解説しない。ただし、awk はプログラミング言語というより、行単位の変換ツールと言った方が適切だと思う。大規模なプログラムを作成するのには、絶対に向かない。今から awk を覚えるよりは、perl か ruby の勉強をした方がよいだろう。
>> コマンド gawk *   perl *   sed *   tr *
>> 読み方 awk *

banner 大きい文字を出力

大きい文字を出力する。画面上に出力し、操作者がわかりやすくするために使う。元々はプリンタ出力の表紙作成用に使われていたと聞いた記憶があるような、ないような。

Solaris や HP-UX など SysV 系 UNIX では以下のような出力になる。
% banner hoge
 #    #   ####    ####   ######
 #    #  #    #  #    #  #
 ######  #    #  #       #####
 #    #  #    #  #  ###  #
 #    #  #    #  #    #  #
 #    #   ####    ####   ######

一方、FreeBSD ではこんなことになってしまう (本当はもっと大きいので、少し縮小してある)。
% banner hoge
                     ###                                                        ###
                     ###                                                        ###
                     ##############################################################
                     ##############################################################
                     ##############################################################
                     ##############################################################
                     ##############################################################
                     ###                          ###
                     ###                           ###
                                                    ####
                                                    ####
                                                     ####
                                                     #####
                                                    ######
                     ###                            ######
                     #####################################
                     ####################################
                     ####################################
                     ###################################
                     #################################
                     #############################
                     ###

                                 ############
                              ###################
                            ######################
                          ###########################
                        ##############################
                       #########               #########
                      ######                      ######
                      ####                           ####
                      ###                             ###
                     ###                               ###
                     ###                               ###
                     ###                               ###
                     ###                              ####
                      ###                             ###
                      ####                           ####
                      ######                      ######
                       #########               #########
                        ###############################
                          ###########################
                           #########################
                              ###################
                                 ############
(略)

FreeBSD では -w オプションで文字幅を指定できるので活用しよう。
% banner -w 28 hoge
       #                 #
       ###################
       ###################
                 #
                 #
       ###########
       ##########
           ###
        #########
       ##       ##
       #         #
       #         #
       ###     ###
         #######
   ##        ##
 ##   ###  ######
 #    ### ##    ##
 #   ###  #      #
 #   ###  ##    ##
 ######    #######
                  ##
           ###
        #########
       ##   #   ##
       #    #    #
       #    #    #
        #   #####
            ####

base64 BASE64 エンコーダ・デコーダ

base64 は、エンコード規則のひとつである BASE64 規格にのっとった変換を行うコマンドである。

文字列をエンコード
% echo 'abc' |base64 -e
YWJjCg==
文字列をデコード
% echo 'YWJjCg==' | base64 -d
abc
ファイルをエンコード
% base64 -e sample.txt
ファイルをデコード
% base64 -d sample.txt
>> コマンド uuencode *   uudecode *   nkf *   openssl *

basename パス名+ファイル名からパス名を削除する

与えられた文字列の最後の / 以降を表示するコマンドである。
% basename /usr/local/bin/vi
vi
% basename /hoge/fuga
fuga
ファイルが実際に存在するかどうかは basename はチェックしない。単に文字列を加工し、結果を出力するだけのコマンドである。

また、
% basename foo.dat .dat
とすると、foo.datから.datを削除したものを表示する。これを使って、
% foreach i ( *.c.orig )
foreach? cp $i `basename $i .orig`
foreach? end
とすると、DOS でいう
COPY *.c.orig *.c
が実現できる (foreach は csh・tcsh のみ。sh・bash は for を使うこと)。これと同じことを basename を使わず行うこともできる。foreach・for の説明を参照。
>> コマンド dirname *   realpath *   for *   foreach *

bash 高機能版 sh。バッシュ。

sh のユーザインタフェース機能を強化したもの。

Linux 方面では、デフォルトのログインシェルは bash になっていることが多い。また、Linux では /bin/sh は /bin/bash のハードリンクとなっているので、sh でも bash でも挙動は同じである。Linux 以外の OS では、sh と bash は別物である。

bash という名前は Bourne-Again SHell の頭文字を取ったもの。sh の作者がボーン (Bourne) 氏 であることから、Bourne と Born (生まれる) をかけて、「生まれ変わったシェル」として命名された。
>> コマンド sh *   csh *   tcsh *
>> 設定ファイル ~/.profile *   ~/.bash_profile *
>> 用語集 リダイレクト *   シェルスクリプト *
>> 読み方 bash *

bc 計算機

計算を行う。
% bc
2+4 (入力)
6
a=34/2 (入力)
a-2 (入力)
15
quit (終了)
⇒ quit の代わりに EOF (Ctrl-d) で終了することもできる。

小数点以下の有効桁数は scale という変数で設定できる (デフォルトは0)。
% bc
2/3
0
⇒ デフォルトでは scale=0 なので小数点以下は表示されない
scale=4
⇒ 小数点以下4桁を表示するよう設定変更
2/3
.6666

ファイルに計算式を記述して、ファイル名を指定してもよい。
% cat sample
5*8
quit
% bc sample
40
さらに標準入力から計算式を指定することもできる。
% echo '9*9' | bc
81
% echo 'scale=4; 9/5; 15' | bc
2.2500
15
⇒ セミコロンでつなぐと複数の計算をさせることができる

使用可能な演算子は以下のとおり。
a + b
a - b
a * b
a / b 商。小数点以下の表示は scale の設定に従う
a % b 剰余。a を b で割ったときの余り
a ^ b べき乗。a を b 回掛け合わせた数。
>> コマンド calc *   dc *   hexcalc *   xcalc *

bdes ファイルを暗号化・復号化する(パイプ)

ファイルを暗号化する。crypt と同じ機能を持つ。sample.dat というファイルを暗号化したい場合は
% bdes < sample.dat > sample.dat.encryped
Enter key: (暗号化のキーを入力)
とする。復号化は、
% bdes -d < sample.dat.encryped > sample.dat.decryped
Enter key: (暗号化時に入力したキーを入力)
FreeBSD の場合、DES をインストールすると /usr/bin/bdes にバイナリが置かれる。
>> コマンド crypt *   openssl *

bdftopcf 

>> コマンド mkfontdir *

beav バイナリエディタ・ビュアー

emacs ライクな操作方法を持つ (が、結構違うところも多い)。日本語は表示できない (エディットはできる)。

画面イメージ
     0: 02 74 3D 00 0C 00 04 01  2E 00 00 00 00 74 3D 00  .t=..........t=.
    10: 0C 00 04 02 2E 2E 00 00  31 75 3D 00 10 00 08 06  ........1u=.....
    20: 6B 65 72 6E 65 6C 00 D3  32 75 3D 00 18 00 08 0C  kernel..2u=.....
    30: 61 63 63 66 5F 64 61 74  61 2E 6B 6F 00 8F 78 C0  accf_data.ko..x.
    40: 33 75 3D 00 18 00 08 0C  61 63 63 66 5F 68 74 74  3u=.....accf_htt
    50: 70 2E 6B 6F 00 8F 78 C0  34 75 3D 00 10 00 08 06  p.ko..x.4u=.....
    60: 61 68 61 2E 6B 6F 00 D3  35 75 3D 00 10 00 08 06  aha.ko..5u=.....
    70: 61 68 63 2E 6B 6F 00 D3  36 75 3D 00 14 00 08 0B  ahc.ko..6u=.....
    80: 61 68 63 5F 65 69 73 61  2E 6B 6F 00 38 75 3D 00  ahc_eisa.ko.8u=.
    90: 14 00 08 0A 61 68 63 5F  70 63 69 2E 6B 6F 00 D3  ....ahc_pci.ko..
    A0: 39 75 3D 00 10 00 08 06  61 68 64 2E 6B 6F 00 D3  9u=.....ahd.ko..
    B0: 3A 75 3D 00 10 00 08 06  61 69 6F 2E 6B 6F 00 D3  :u=.....aio.ko..
    C0: 3B 75 3D 00 10 00 08 06  61 6D 72 2E 6B 6F 00 D3  ;u=.....amr.ko..
    D0: 3C 75 3D 00 14 00 08 08  69 66 5F 61 6E 2E 6B 6F  xu=.....if_an.ko
    E0: 00 B9 10 D3 3D 75 3D 00  14 00 08 09 69 66 5F 61  ....=u=.....if_a
    F0: 74 68 2E 6B 6F 00 15 D3  3F 75 3D 00 14 00 08 09  th.ko...?u=.....
   100: 69 66 5F 61 75 65 2E 6B  6F 00 24 D3 B3 76 3D 00  if_aue.ko.$..v=.
   110: 14 00 08 09 69 66 5F 61  78 65 2E 6B 6F 00 15 D3  ....if_axe.ko...
   120: B4 76 3D 00 14 00 08 09  69 66 5F 62 66 65 2E 6B  .v=.....if_bfe.k
   130: 6F 00 1A D3 B5 76 3D 00  14 00 08 09 69 66 5F 62  o....v=.....if_b
   140: 67 65 2E 6B 6F 00 16 D3  B6 76 3D 00 14 00 08 09  ge.ko....v=.....
   150: 62 72 69 64 67 65 2E 6B  6F 00 73 CE B7 76 3D 00  bridge.ko.s..v=.
BEAV  I kernel       File: /boot/kernel [RW]    CURSOR=00000000, 1   HEX 8   0H:


主要キーバインド
C-f 1文字進む
C-b 1文字戻る
C-n 1行進む
C-p 1行戻る
C-x C-s セーブ
C-x C-c 終了
ESC s 検索
ESC t 次検索
C-x i 1バイト挿入
ESC d 1バイト削除
C-g 現在入力中のコマンドを抜ける
ESC ? ヘルプを表示
C-x 2 ウィンドウを上下に分割
C-x n 次ウィンドウに移動
ESC a ASCII 表示モードに切り替え
ESC < バッファの先頭に移動
ESC > バッファの終端に移動

オンラインマニュアルが貧弱なのには困るが、(FreeBSD では) 詳しいドキュメントが /usr/local/share/doc/beav/beav.txt に書いてある (英文)。
>> コマンド hexdump *   hd *   od *

bfilter 個人向け HTTP proxy (プロキシ)

個人用途向け HTTP proxy。主に、邪魔なバナー広告・画像・IFRAME などを削除するために使う。

ウリは以下の通り。
  • 正規表現で柔軟な削除設定が可能
  • HTTP/1.1 に対応 (パイプライン・持続的接続にも対応)
  • Javascript エンジンを搭載しているため、質の高い判断が可能
  • 新しいウィンドウを開くための target="_blank" 属性を削除可能

最近の mozilla や FireFox は画像ブロック機能を持っているので、そちらも検討するとよい。

デフォルトのルール設定では、
  • (.*/)?banners?.*
  • (.*/)?ad[sv]?(/|\.).*
  • (.*\.)?ad[0-9]*\..*
などの正規表現にマッチする URL がブロックされるようになっている。試しに朝日新聞と読売新聞のサイトを閲覧してみたところ、一部の広告が表示されないようになっており、効果はあるようだ。ただし毎日新聞のサイトを閲覧してみると記事が何も表示されなかった。デフォルト設定ではルールが厳しすぎるため、よく閲覧するサイトごとに手作業でルールを決めないと使いものにならないかもしれない。

なお、UNIX の GUI 版もあるが、GUI 上からブロックの ON・OFF などを設定できるのが便利な程度である。

bg 指定したジョブをバックグラウンドで実行する。シェルの内部コマンド。

ジョブ番号を指定しないとカレントジョブが操作対象になる。bg を使うということは、command & で起動するのと同じこと。詳しくは jobs を参照。
>> コマンド fg *   jobs *

biff メールの到着を知らせるかどうかを設定する。

biff コマンドは、メールが届いた瞬間に、
New mail for foo@bar.com has arrived:
----
From: foo@bar.com <hogehoge>
Subject: Hello!

Hi. I'm hogehoge....
のような誰からどういう内容のメールが届いたかという情報を表示する。

引数に y か n を指定することで、biff の機能を切り替えることができる。
% biff y
⇒ メールの到着を知らせる
% biff n
⇒ メールの到着を知らせない
% biff b
⇒ BEEP 音でメールの到着を知らせる
引数なしで実行すると、現在の設定を表示する。
% biff
n
⇒ メールの到着を知らせない設定になっているということ

この機能はシェルが出力する
You have new mail.
というメッセージとは全く別のものである。

biff の出力は結構うざったいので biff n か biff b にしておき、シェルのメッセージや xbiff・xpbiff を使った方がよいのではないかと思う。

関連: http://68user.blog27.fc2.com/blog-entry-23.html biff はなぜ動く?
>> コマンド xbiff *   xpbiff *
>> Cシェル変数 mail *
>> 読み方 biff *

bindkey tcsh の機能をキーに割り付ける。tcsh の内部コマンド。

引数なしで実行すると、現在のキーバインドを表示する。例えば、
% bindkey
Standard key bindings
"^@" -> set-mark-command
"^A" -> beginning-of-line
"^B" -> backward-char
...(略)...
だと、^@(Ctrl-@) はマーク、^a (Ctrl-a) は行頭に移動、^b (Ctrl-b) は一文字戻る、という意味。-l オプションを付けると、全ての機能とその解説の一覧が表示される。

例えば ^r にはデフォルトでは redisplay という機能が割り振られている。これを後方インクリメンタルサーチである i-search-back に変えるには
% bindkey ^R i-search-back
とすればよい。例えば、これまで
% script test
% man xscreensaver
% coco -q < sample.dat
というコマンドを実行していたとする。ここで Ctrl-R を押すと、コマンドラインが
% (カーソル位置)
bck:
となる。ここで s をタイプすると、一番近い s を含むヒストリを探す
% coco -q < sample.dat
bck:s
続いて c をタイプすると、sc を検索する。
% man xscreensaver
bck:sc
さらに r を押すと
% script test
bck:scr
となる。script test を実行したい場合はそのままリターンキーを押せばよいし、C-f、C-b などで編集することもできる。ESC キーを押せば検索モードを抜ける。

なお、bash では標準で C-r に後方インクリメンタルサーチが割り振られている。
>> コマンド tcsh *

bison 構文解析パーサ生成プログラム

yacc の上位互換プログラム。GNU が作成・配布している。
>> コマンド lex *   flex *   yacc *
>> 読み方 bison *

bonnie ディスクベンチマーク

ディスクのベンチマークプログラム。事前にディレクトリを作成し、そこにファイルを作成することでベンチマークを行う。root 権限は必要なく、一般ユーザで実行可能。

デフォルトでは 100MB のファイルを作成し、シーケンシャル・ランダムアクセスの入出力を行う。
% mkdir /bonnie-dir
% bonnie -d /bonnie-dir
File '/bonnie-dir/Bonnie.1690', size: 104857600
(略)
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
          100  4514  8.2  4715  3.2  4606  3.3 41965 99.5 239622 99.9 25600.5 97.3

bonnie の後継である bonnie++ というプログラムもある。bonnie と bonnie++ の比較は bonnie++ の項目を参照。
>> コマンド bonnie++ *

bonnie++ ディスクベンチマーク

bonnie の後継であるディスクベンチマークプログラム。機能的な差異は以下の通り。
  • 2GB をこえるファイルサイズを扱える。
  • bonnie は 1つのファイルしか生成しないが、bonnie++ は複数のファイルを生成するため、ファイル生成・削除のスピードを計測できる。

bonnie++ を実行すると、カレントディレクトリにファイルを生成し始めるので、ディレクトリを掘ってそれを -d オプションで指定して実行するとよいだろう。また、bonnie と同様に一般ユーザ権限で実行が可能である。

bonnie++ はデフォルトでは 300MB のファイルを生成する。また、デフォルトでは 16,000 のファイルを生成する。下記の結果では、files=16 となっているが、実際には 1,000 倍した値が使われる。

% mkdir bonnie++
% bonnie++ -d bonnie++/
(略)
Version 1.93c       ------Sequential Output------ --Sequential Input- --Random-
Concurrency   1     -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine        Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP  /sec %CP
myhost         300M   194  99  2110   1  1630   1   364  98  4803   3  79.1   2
Latency             78667us     520ms     817ms   36437us     184ms   32417ms
Version 1.93c       ------Sequential Create------ --------Random Create--------
myhost              -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
              files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                 16  8038  39 21130  43 11179  33  8727  41 21475  51  9720  36
Latency             25107us    2758us   11912us   27388us   70667us    3901us
1.93c,1.93c,myhost,1,1069276163,300M,,194,99,2110,1,1630,1,364,98,4803,3,79.1,2,16,
,,,,8038,39,21130,43,11179,33,8727,41,21475,51,9720,36,78667us,520ms,817ms,36437us,
184ms,32417ms,25107us,2758us,11912us,27388us,70667us,3901us
>> コマンド bonnie *

bsdiff バイナリパッチ作成 (差分・差異・比較)

bsdiff はバイナリファイルのパッチ (差分ファイル) を生成する。
% bsdiff bin.old bin.new bin.bsdiff
⇒ bin.old と bin.new の差分を抽出し、パッチファイル bin.bsdiff を生成する。
生成したパッチをあてるには bspatch を使う。
% bspatch bin.old bin.new bin.bsdiff
⇒ bin.old にパッチファイル bin.bsdiff をあて、bin.new を生成する。

同種のコマンドとして xdelta があるが、bsdiff・bspatch の作者は「bsdiff が生成するパッチファイルは、xdelta の 50〜80% のサイズである」と主張している。実際にパッチサイズはかなり小さくなるようだ。

ちなみにbsdiff・bspatch の bs は「Binary Software」の略。

テキストファイルのパッチ生成・パッチ適用には diff・patch コマンドを使うこと。
>> コマンド bspatch *   xdelta *   diff *   patch *

bspatch バイナリパッチ適用

詳細は bsdiff を参照。
>> コマンド bsdiff *

builtins tcsh の内部コマンド一覧を表示

>> コマンド tcsh *

bzip2 gzip より圧縮率の高い圧縮・伸長ツール (bunzip2)

gzip は compress より圧縮率が高いが、bzip2 は gzip よりさらに圧縮率が高い。いくつかのファイルを圧縮してみた結果、bzip2 は gzip より 2〜15% 程度圧縮率が高かった。しかし、その分圧縮にかかる時間は4倍くらいになってしまうので、用途を考えて bzip2 を使うべきか gzip を使うべきかを決めるとよいだろう。

bzip というものもあるが、これは bzip version 1 であるので、bzip2 を使った方がよい。bzip2 は Linux 方面で普及しているが、*BSD 方面ではまだ標準の地位を得ていない。圧縮したファイルを配布する際は、bzip2 版と gzip 版を用意しておくとよいだろう。

使い方は、gzip とほとんど同じである。
% bzip2 file
で、圧縮された file.bz2 が生成される。伸長するには
% bunzip2 file.bz2
または
% bzip2 -d file.bz2
とすればよい。

オプション: (これも gzip と似ている)
-c 圧縮・伸長の結果を標準出力に書き出す。ファイルへの書き込みは行なわない
-d 伸長する
-v バーボーズモード
-1 圧縮にかかる時間を短くする
-9 圧縮率の高い圧縮方法を使う

bunzip2 は伸長ツールだが、bzip2 -d としても全く同じである。
>> コマンド gzip *   compress *   tar *

cal カレンダーを表示する

y(数字) y年のカレンダーを表示する
% cal 1998
                             1998

      January               February               March
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
             1  2  3   1  2  3  4  5  6  7   1  2  3  4  5  6  7
 4  5  6  7  8  9 10   8  9 10 11 12 13 14   8  9 10 11 12 13 14
11 12 13 14 15 16 17  15 16 17 18 19 20 21  15 16 17 18 19 20 21
18 19 20 21 22 23 24  22 23 24 25 26 27 28  22 23 24 25 26 27 28
25 26 27 28 29 30 31                        29 30 31

       April                  May                   June
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
          1  2  3  4                  1  2      1  2  3  4  5  6
 5  6  7  8  9 10 11   3  4  5  6  7  8  9   7  8  9 10 11 12 13
12 13 14 15 16 17 18  10 11 12 13 14 15 16  14 15 16 17 18 19 20
19 20 21 22 23 24 25  17 18 19 20 21 22 23  21 22 23 24 25 26 27
26 27 28 29 30        24 25 26 27 28 29 30  28 29 30
                      31
(略)
⇒ 1998年のカレンダーを表示
m y(数字) y年m月のカレンダーを表示する
% cal 6 1999
     June 1998
Su Mo Tu We Th Fr Sa
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
⇒ 1999年6月のカレンダーを表示
% cal sep 1998 September 1998 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
⇒ 月は英語でも指定可能
-y 今年のカレンダー(1〜12月)を表示
-j 1月1日からの日数を表示する

ちなみに 1752年9月に、ユリウス歴からグレゴリオ歴に(イギリスが)移行した。そのため、1752年9月3日〜13日は表示されない。
% cal 9 1752
   September 1752
Su Mo Tu We Th Fr Sa
       1  2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
>> コマンド xcalender *

calc 簡易計算機

>> コマンド bc *   dc *   hexcalc *   xcalc *

cat ファイルの内容を表示する(パイプ)。複数のファイルを連結する

指定したファイルの内容を表示する。ファイルが長くて一画面に収まらない場合は、more や less などのページャと呼ばれるプログラムを使う方がよい。

-n 行番号を表示
-b 行番号を表示。空行をカウントしない
-s 連続する空行を1行の空行として表示
-v コントロールコードを文字列 (^X や M-x など) として表示する
-t -v オプションに加えて、ダブを ^I で表示する
-u 出力をバッファリングしない

cat コマンドは、split コマンドで分割したファイルを結合するときにも使われる。
% split sample
% ls x??
xaa xab xac
% cat xaa xab xac > sample2
>> コマンド more *   less *   split *
>> 読み方 cat *

catman オンラインマニュアルの整形を行う

man で表示されるマニュアルは、nroff というマクロ言語の形式で用意されている。

man コマンドを実行すると、nroff 形式のファイルを nroff や groff コマンドで変換して、catman というプレインテキスト形式に整形する。この変換作業には少し時間がかかるので、一度参照されたマニュアルは catman 形式で保存しておき、二度目からは catman 形式のファイルを表示することで man の実行が速くなる。

catman コマンドは、事前に整形作業を行って、プレインテキストを作成しておくためのコマンドである。一度も見たことがないマニュアルを初めて表示するときに時間がかかるのが嫌なら、事前に catman コマンドを実行しておくとよい。ただし、その分ディスク容量を喰うことになる。

catman を使わなくても、一度表示したマニュアルは man コマンドが自動的に整形済のプレインテキスト版を保存してくれるので、man の速度に不満がないなら catman を使う必要はない。

具体的には
% catman /usr/share/man/man1/
⇒ /usr/share/man/man1/ 以下のマニュアルを整形し、/usr/share/man/cat1/ に書き込む。
% catman /usr/share/man/ja/man8/
⇒ /usr/share/man/ja/man8/ 以下のマニュアルを整形し、/usr/share/man/ja/cat8/ に書き込む。
% catman /usr/X11R6/man/
⇒ /usr/X11R6/man/ 以下のマニュアル (全セクション) を整形し、/usr/X11R6/man/cat?/ に書き込む。
などと指定する。しかし一般的にはオンラインマニュアルは、全ユーザが参照する共用のものなので、root になって man ユーザの権限で
# su man -c "catman /usr/share/man/man1"
⇒ /usr/share/man/man1 以下のマニュアルを整形する。su コマンドを使って、man の権限で catman を実行する。
とするとよいだろう。
>> コマンド man *   jcatman *   su *

cc C コンパイラ

FreeBSD や Linux など、フリーの PC-UNIX では標準の C コンパイラが gcc になっている。

それ以外の UNIX の C コンパイラは、ごく一部の基本的なオプションは gcc と共通であるが、一般的に互換性はないと思った方がよいだろう。
>> コマンド gcc *   lint *   unifdef *
>> 読み方 cc *

cccc C言語・C++・Java ソースコードステップカウンタ (行数カウント・ステップカウント・ステップ数)

C言語・C++・Java のソースコードのステップ数を調べるツール。
% cccc *.c
と直接ファイルを引数で指定するか、あるいは
% find . -name \*.c -print > source.list
% cccc -f source.list
などとソースファイル名一覧のファイルを生成し、-f オプションで指定することでステップカウントを行う。カウント結果は、カレントディレクトリに出力される cccc.htm という HTML ファイルに記述されている。

このファイルに出力される情報の中から、主要なものを以下に解説する。
Number of modules (NOM) 1 モジュール数。モジュールがどういう単位なのかわからない。
Lines of Code (LOC) 887 コード行数。コメント行・空行・空白行は含まない。
McCabe's Cyclomatic Number (MVG) 156 マッケーブの循環的複雑度。要は各関数が単純な親子関係であれば循環度が低く、どれが親かわからないような複雑な呼ばれ方をする関数だと循環度が高いらしい。10 以下だと単純なよい構造、50 を越える場合はテスト不能、その中間は複雑度が高い、らしい。
Lines of Comment (COM) 203 コメントの行数。純粋にコメントのみからなる行数であって、コードの末尾にコメントを記述した場合はカウントされないようだ。
LOC/COM (L_C) 4.369 コード行数 ÷ コメント行数
MVG/COM (M_C) 0.768 マッケーブの循環的複雑度 ÷ コメント行数。
Henry-Kafura/Shepperd measure (visible) (HKSv) 0 意味がわかりません。
Henry-Kafura/Shepperd measure (concrete) (HKSc) 0 意味がわかりません。
Henry-Kafura/Shepperd measure (inclusive) (HKS) 0 意味がわかりません。
Lines of Code rejected by parser (REJ) 227 cccc が解析できなかった行数。特に C言語や C++ の場合、マクロの定義次第でいくらでも意味不明のコードを記述できる。しかし cccc はマクロ展開をしてくれないため (そしてインクルードファイルも読んでくれないため)、ちょっと変わった書き方に出くわすと結構な頻度でエラー扱いとし、その行をスキップして処理を続行してしまう。解析に失敗してもコード行数に加えてくれればよいと思うのだが、なぜかそうはしてくれない。

また、関数ごとに LOC・MVG・COM・L_C・M_C の値を算出する。

なお、実際の行数 (コメント・空行も含む) は出力してくれないので、wc コマンドで自分で数えよう。

ちなみに「いまどき行数なんて数えるのか? 昭和の時代じゃあるまいし」と学生時代に思っていた当ページ管理人。今の仕事ではきっちり数えさせられています。やだやだ。

cd カレントディレクトリを変更する。シェルの内部コマンド。

カレントディレクトリとは、「今 自分がいるディレクトリ」のこと。

移動したいディレクトリを引数で指定すると、そのディレクトリに移動する。
% pwd
/home/hogehoge
⇒ 現在のカレントディレクトリは /home/hogehoge
% cd lib
% pwd
/home/hogehoge/lib
% cd /usr/local
% pwd
/usr/local
引数なしで起動するとホームディレクトリに移動する。
% cd
% pwd
/home/hogehoge
⇒ 引数を省略して cd を実行すると、ホームディレクトリへ移動
% cd ..
% pwd
/home
⇒ 「..」は「一つ上のディレクトリ」を意味する

引数に「-」を指定すると、一つ前のディレクトリに戻る (これが機能するかどうかは OS による)。ただし、2個以上前のディレクトリまでさかのぼって移動することはできない。
% cd /dir1
% cd /dir2
% pwd
/dir2
% cd -
% pwd
/dir1
⇒ ひとつ前のカレントディレクトリに戻った
% cd -
% pwd
/dir2
⇒ 連続して cd - すると、/dir1 と /dir2 を行き来することになる

カレントディレクトリは各プロセス固有の情報である。シェルからあるコマンドを実行し、その中でカレントディレクトリを変更しても、シェル自体のカレントディレクトリは移動しない。つまり、
#!/bin/sh
cd /
というスクリプトをシェル上から実行しても、シェル自体のカレントディレクトリは変わらないということ。どうしてもというなら、
#!/bin/sh
echo cd /
として、
% eval `hoge.sh` (バッククォートで囲む)
とすればよい。

また、カレントディレクトリは各プロセス固有の情報であるということを利用して、
% (cd /foo; tar zcf archive.tgz .)
などとすると、シェルのカレントディレクトリを変えずに /foo 以下のアーカイブを作成することが
できる。カッコで括った部分は別のシェル (子プロセス) として実行されるので、カッコ内でどれだけカレントディレクトリを変更しても、現在のシェルには影響がない。

なお、これは
% pushd /foo; tar zcf archive.tgz . ; popd
% cd /foo; tar zcf archive.tgz . ; cd -
と等価である。
>> コマンド chdir *   pwd *   mv *   cp *
>> 用語集 プロセス *
>> 読み方 cd *

cda CDプレイヤー

>> コマンド cdcontrol *   xmcd *   cdplay *

cdcontrol CDプレイヤー

おそらく FreeBSD にしかないコマンド。CD ドライブを操作できる。

-f dev CD のデバイス名を指定する。
デバイス名は wcd0、cd0、mcd0 など。例えば CD ドライブのデバイスが wcd0 の場合、-f /dev/wcd0 でも -f wcd0 でもよい。
% chmod 666 /dev/wcd0
が必要かも。環境変数 DISC に CD のデバイス名を指定しておくと、-f オプションでいちいちデバイス名を指定する必要がなくなる。
命令
play トラック 指定したトラックから演奏を開始。トラックを省略するとトラック 1 から演奏する
pause 演奏を中断する
stop 演奏を停止する
resume 演奏を再開する
info CDの演奏時間などの情報を表示
volume [0-255] [0-255] 左右のボリュームを設定。ボリュームは0-255で指定
volume mute ボリュームを0にする
volume mono モノラルで出力
volume stereo ステレオで出力
volume left 左チャンネルだけ出力
volume right 右チャンネルだけ出力
eject CD をイジェクトする
引数で命令を書いてもいいし (cdcontrol play 4 など)、引数なしで起動すると対話モードに入るので、そこで命令を書いてもいい。
>> コマンド cda *   cdplayer *   workman *   xmcd *   cdplay *   tosha *

cdplay CDプレイヤー

起動方法は以下の通り。
% cdplay デバイス名
>> コマンド cda *   cdplayer *   workman *   xmcd *   cdcontrol *

cdplayer CDプレイヤー

>> コマンド cda *   cdplay *   cdcontrol *   xmcd *   workman *

cflow Cのソースを解析して、どの関数内からどの関数を読んでいるか表示する。

>> コマンド gcc *

chdir カレントディレクトリを変更する。cd と全く同じ

>> コマンド cd *

chflags ファイルのフラグを変更する

BSD 系 UNIX にはパーミッションとは別にファイルフラグという仕組みがあり、変更禁止、追加禁止などの設定をすることができる。なお、ファイルフラグは chmod のパーミッションとは全く別のものである。
  • arch アーカイブフラグ
  • dump ダンプフラグ
  • sappnd システムの追加専用フラグ
  • schg システムの変更禁止フラグ
  • uappnd ユーザの追加専用フラグ
  • uchg ユーザの変更禁止フラグ
また、これらの先頭に no をつけるとフラグを消す意味がある。

ファイルを変更禁止にするには
% chflags uchg file
元に戻すには
% chflags nouchg file
とする。例えば FreeBSD では /kernel は chflags schg /kernel とされているので、mv や rm する際は
# chflags noschg /kernel
# rm /kernel
などと、一旦フラグを OFF にしなければならない。他にも、init・chsh コマンドなどに schg フラグが立てられている。現在のファイルフラグの値は ls -lo で見ることができる。
% ls -lo /kernel /sbin/init /usr/bin/chsh
-r-xr-xr-x  1 root  wheel  schg 1301840 Jun 20 20:54 /kernel
-r-x------  1 bin   bin    schg  204800 Oct 13 21:56 /sbin/init
-r-sr-xr-x  6 root  bin    schg   36864 Mar  4  1999 /usr/bin/chsh
なお、ファイルフラグは 4.4BSD から追加された。おそらくファイルフラグを実装しているのは FreeBSD・NetBSD・OpenBSD・BSDI のみだろうと思われる。
>> コマンド ls *   rm *   chmod *

chgrp ファイルの属するグループを変更する

% chgrp group file
⇒ ファイル file のグループを groupに変更する
詳しい説明は chown で。
>> コマンド chown *

chmod ファイル・ディレクトリの属性を変更する。

全てのファイル・ディレクトリにはパーミッションという属性があり、どのユーザが読むことができ、どのユーザが書き込めるか、などのアクセス権限を設定できる。現在のパーミッションの値は ls -l で調べることができる。
% ls -l sample.dat
-rwxr-xr-- 1 user group 402 May 26 1997 sample.dat
の「rwxr-xr--」がパーミッションである(その前の「-」はファイルタイプ。とりあえずは無視)。

読み方は、まずパーミッションの表示を3文字ごとに区切って、「rwx」「r-x」「r--」とする。
  • 1番目のセクション (rwx) はファイル所有者 (この場合は user) にとってのパーミッション
  • 2番目のセクション (r-x) はファイル所有グループ (この場合は group) にとってのパーミッション
  • 3番目のセクション (r--) はそれ以外のユーザにとってのパーミッション
となる。「r」は読み込み可能属性、「w」は書き込み可能属性、「x」は実行可能属性を意味する。

つまり
-rwxr-xr-- 1 user group 402 May 26 1997 sample.dat
は、
  • ユーザ user は、sample.dat を読めるし、書き込めるし、実行できる
  • グループ group に属するユーザは、sample.dat を読めるし、実行できるが、書き込みはできない
  • その他のユーザは、sample.dat を読めるが、書き込みと実行はできない
ということを意味する。

chmod はパーミッションを変更するコマンドだが、そのファイル・ディレクトリの所有者しかパーミッションを変更できない。上記の例だと、sample.dat のパーミッションを変更できるのはユーザ user だけである。

パーミッションの指定方法には絶対方式と相対方式がある。絶対方式は8進数の数字によって指定する。
  • 0400 所有者が読み込める
  • 0200 所有者が書き込める
  • 0100 所有者が実行できる
  • 0040 groupに属するユーザが読み込める
  • 0020 groupに属するユーザが書き込める
  • 0010 groupに属するユーザが実行できる
  • 0004 その他のユーザが読み込める
  • 0002 その他のユーザが書き込める
  • 0001 その他のユーザが実行できる
また、この他に suid・sgid・sticky bit があるが、説明は後述。

ファイル sample.dat を所有者だけが読み込み・書き込みできるようにするには 0400+0200+0100=0700 で、
% chmod 0700 sample.dat
とする。ファイルsampleを所有者が読み込み・書き込み・実行できて、groupに属するユーザとその他のユーザは読み込み・実行のみできるようにするには、0400+0200+0100+0040+0010+0004+0001=0755 で
% chmod 0755 sample
とする (最初の 0 を省略して 700・755 でもよい)。

一方、相対方式は、
  • u,g,o,a … 所有者・グループに属するユーザ・その他のユーザ、全員
  • r,w,x … 読み込み属性・書き込み属性・実行属性
  • +/- … 属性を ON にする/OFF にする
を使う。これは現在のパーミッションの一部だけを変更する際に便利。
% chmod +x file
⇒ file の実行属性を ON にする
% chmod go-w file
⇒ file のグループとその他のユーザの書き込み属性を OFF にする
% chmod a-x file
⇒ file の全員の実行属性を OFF にする (chmod ugo-x file と同じ)
ただし、相対方式と言っても、
% chmod u=rwx,go=rx file (chmod 755 と同じ)
のように完全な (相対的でない) パーミッションを設定することはできる。

なお、シンボリックリンクのパーミッションは意味を持たない。
lrwxrwxrwx 1 user group 3 Aug 1 16:14 file-b -> file-a
でも
l--------- 1 user group 3 Aug 1 16:14 file-b -> file-a
でも全く違いはない。有効なのはリンク先の file-a のパーミッションである。chmod に -RH オプションを付けると、シンボリックリンクのリンク先のファイルの属性を変更する。

これまで r(400)・w(200)・x(100) は読み込み・書き込み・実行属性であると説明してきたが、これはファイルに対する権限であって、ディレクトリに対しては意味が少し違い、
  • r … そのディレクトリの下にあるファイルの一覧を取得できるかどうか
  • w … そのディレクトリの下に、ファイルを新規作成できるかどうか。
また、そのディレクトリの下に存在するファイルを、消去できるかどうか。
  • x … そのディレクトリの下にあるファイルにアクセスできるかどうか
という意味を持つ。
  • ディレクトリに「r」が設定されていると、ls コマンドなどで、その下に存在するファイルの一覧を取得できる。
  • ディレクトリに「w」が設定されていると、ディレクトリの下にファイルを新規作成できるし、ディレクトリの下に存在するファイルを rm コマンドで削除できる。
  • ディレクトリに「x」が設定されていると、その下のファイルの情報を見たり、ファイルに対して書き込み・読み込みができる

実験
では実際に例を示そう。
% mkdir dir
% echo hogehoge > dir/file
% chmod 700 dir
ディレクトリ dir を作成し、その下にファイル file を作成する。file の中身は「hogehoge」である。
% ls dir
file
⇒ ディレクトリ dir 下のファイル一覧が取得できる
% ls -l dir
-rw-r--r-- 1 user group 9 Oct 10 14:57 file
⇒ ディレクトリ dir 下のファイルの情報が取得できる
% ls -l dir/file
-rw-r--r-- 1 user group 9 Oct 10 14:57 file
⇒ ファイル名を直接指定しても大丈夫
% cat dir/file
hogehoge
⇒ ディレクトリ dir 下のファイルの内容が取得できる
いずれも普通にアクセスできることがおわかりだろう。

では、ディレクトリ dir のパーミッション「r」だけを立てて、同じことをしてみよう。
% chmod 400 dir
% ls dir
file
⇒ ディレクトリ dir 下のファイル一覧が取得できる
% ls -l dir
ls: dir/file: Permission denied
⇒ ディレクトリ dir 下のファイルの情報は取得できない
% ls -l dir/file
⇒ ファイル名を直接指定してもダメ
% cat dir/file
cat: dir/file: Permission denied
⇒ ディレクトリ dir 下のファイルの内容が取得できない
ls で dir の下のファイル一覧は取得できるが、ls -l で各ファイルの情報を取得することはできない。dir の下のファイルを表示することもできない。

次に、ディレクトリ dir のパーミッション「x」だけを立てて、同じことをしてみよう。
% chmod 100 dir
% ls dir
ls: dir: Permission denied
⇒ ディレクトリ dir 下のファイル一覧は取得できない
% ls -l dir
ls: dir: Permission denied
⇒ ディレクトリ dir 下のファイルの情報も取得できない
% ls -l dir/file
-rw-r--r-- 1 user group 9 Oct 10 14:57 file
⇒ ファイル名を直接指定すれば大丈夫
% cat dir/file
hogehoge
⇒ ディレクトリ dir 下のファイルの内容は取得できる
「r」を落として「x」を立てると、ls で dir の下のファイル一覧が取得できなくなった。しかしファイル名を直接指定すると、ls -l も有効だし、ファイルの内容も表示できる。

普通、ディレクトリは他ユーザに対して「r-x」としておけばよい。もしディレクトリの下にアクセスしてほしくなければ「---」にすればよいだろう。「r」だけにすると、ファイル一覧は取得できるが、そのファイルの情報を見たり、ファイルにアクセスすることはできなくなる。一方「x」だけを立てると、ファイル一覧は取得できないが、ファイルにアクセスすることはできる、というわけだ。

setuid・setgid・sticky bit
さて、先に少し触れたが、
4000 user s-bit を立てる (setuid・suid)
2000 group s-bitを立てる (setgid・sgid)
1000 sticky bit を立てる
というものがある。
% chmod 4755 file
あるいは
% chmod u+sx file
で setuid を立てることができ、
% chmod 2755 file
あるいは
% chmod g+sx file
で setgid を立てられる。setuid・setgid の意味については setuid の項を参照してほしい。
>> 用語集 setuid *

sticky bit というのは、ディレクトリの下にあるファイルの削除に関する設定である。例えば /tmp ディレクトリを考えてみよう。/tmp は一時ファイルを作成するためのディレクトリで、誰でもファイル・ディレクトリを作成できる。しかし /tmp のパーミッションを 777 にすると、あるユーザが作ったファイルを他のユーザが消すことができてしまう。そこで /tmp のパーミッションを 777 にし、さらに sticky bit を立てる。すると、
  • 誰でもそのディレクトリの下にファイル・ディレクトリを新規作成できる
  • しかし、それを消せるのは作成したユーザ (ファイル・ディレクトリのオーナー) のみ
となる。実際、/tmp は sticky bit が立っている。
% ls -ld /tmp
drwxrwxrwt 7 bin bin 1024 Oct 10 10:24 /tmp
最後の「rwt」の「t」が sticky bit を表している。
% chmod 1777 dir
% chmod a+rwxt dir
などで sticky bit を ON にできる。

昔の UNIX の sticky bit というのは、実行ファイルに対して設定するものであった。頻繁に使用するプログラムについて このビットを立てておくと、常にメモリ上にバイナリを保存しておく効果があった。しかし今では仮想記憶の発達により、意味をなさなくなったので、ファイルに対してこのビットを立てても無視される。「sticky」は「貼り付けておく」という意味であるが、現在では「sticky」という意味はなく、名前だけが残っているわけである。

なお、BSD 系 UNIX には、chmod のパーミッションとは全く別に、ファイルフラグという概念がある。これは chflags コマンドで設定できる。
>> コマンド ls *   chown *   chgrp *   umask *   ln *   chflags *
>> 読み方 chmod *

chown ファイルの所有者、所有グループを変更する

ファイル・ディレクトリの所有者(オーナー)、所有グループを変更する。所有者を変更できるのは root のみであるが、グループはファイルのオーナーなら変更できる可能性がある(オーナーが複数のグループに属している必要がある)。
# chown user file
ファイル file の所有者をユーザ user に変更する
% chown user:group file
ファイル file の所有者/グループを user/group に変更する
% chown :group dir
ディレクトリ dir のグループを group に変更する

自分がどのグループに属しているかは、id コマンドでわかる。
% id
uid=1001(hoge) gid=1001(hoge) groups=1001(hoge), 0(wheel), 5(operator)
のとき、
% touch sample
としてファイルを新規作成すると、
% ls -l sample
-rw-r--r-- 1 hoge hoge 0 Feb 1 13:47 sample
となる。このとき、
% chown :グループ名 sample
で sample の所有グループを変更できるが、このときグループ名として指定できるのは hoge・wheel・operator である。
>> コマンド chgrp *   chmod *   id *
>> 読み方 chown *

chpass ユーザの個人情報 (ログインシェル・リアルネームなど) を変更する。

ログインシェルなどの個人情報を変更する。

chpass を引数なしで実行すると、環境変数 EDITOR に設定されているエディタが起動されるので、
Shell: ...
という項目を書き換えてエディタを終了すればよい。tcsh にしたいなら
Shell: /usr/local/bin/tcsh
とする。

ログインシェルを変更したいだけなら、コマンドラインから
% chsh -s tcsh
% chsh -s /usr/local/bin/tcsh
としてもよい。

ログインシェルとして指定できるのは /etc/shells の中に書かれているものだけである。
>> コマンド chsh *   passwd *   vipw *
>> 環境変数 EDITOR *
>> 設定ファイル /etc/shells *   /etc/passwd *
>> 用語集 NIS *

chsh ログインシェルを変更する

FreeBSD では chsh は chpass と全く同じである。説明は chpass の項を参照。
>> コマンド chpass *

cjpeg 画像ファイルを JPEG 形式に変換する

>> コマンド xv *   convert *

cksum ファイルのチェックサムを表示する

-o デフォルトのアルゴリズムではなく、古いアルゴリズムを使う
% cksum sample
123456789 10000 sample
⇒ チェックサムは 123456789、ファイルサイズは 10000、ファイル名は sample
cksum は古いコマンドなので、md5 や openssl dgst を使うことをお勧めする。
>> コマンド md5 *   openssl *

clear 画面の消去

clearはシェルスクリプトで、内容は
#!/bin/sh -
exec tput clear
となっている。

cmp 2つのファイルの比較。最初に違いが見つかった行番号と文字数を表示する。

cmp はあまり多機能ではないので、2つのファイルが違うものかどうかを知りたいときだけ使うといいだろう。
>> コマンド comm *   diff *

coco コード変換、コード判定を行う(パイプ)

-l 対応しているコードの一覧を表示
-q 指定ファイルの中で使われているコードの種類を判定する
% cat sample.dat | coco -q
In (*euc-japan*unix): 4923 bytes
⇒ sample.euc は EUC-JP であることがわかる。

昔の FreeBSD では、coco は mule のパッケージに含まれていたが、mule が emacs に統合されてからは mule-common パッケージ内に含まれている。
>> コマンド nkf *   qkc *   iconv *   euctosj *

col エスケープシーケンスを取り除く(フィルタ)

オンラインマニュアルは、下線や太字の表示のためのエスケープシーケンスが含まれているので、
% man ls > ls.txt
などとしても ls.txt はプレインテキストにはならず、読みづらい。col を使うとエスケープシーケンスを取り除き、プレインテキストに整形できる。
% man ls | col -b > ls.txt
とすることで、ls のオンラインマニュアルをプレインテキストに変換して ls.txt に書き込む。

FreeBSD の col は日本語に対応していないので、jman を使う場合は colcrt コマンドを使って
% jman ls | colcrt > ls.txt
とすればよい。

なお、col -b や colcrt は、
% perl -pe 's/(_\x08|\x08\x08..|\x08.)//g'
と等価である。
>> コマンド man *

comm 2つのファイルの違いの表示

ファイル名に - を指定すると標準入力から読み込む。

comm は比較対象ファイルがあらかじめ辞書順にソートされている必要がある。普通はいちいちソートするのは面倒なので、diff を使う方がよいだろう。
>> コマンド cmp *   diff *

complete コマンドの引数の補完の設定をする。tcsh の内部コマンド

tcsh は Ctrl-D と TAB で補完機能が使えるが、デフォルトではコマンドとファイル・ディレクトリのみが補完対象となっている。しかし、
  • telnet・rlogin … ホスト名
  • printenv … 環境変数
  • jlatex … *.tex
  • rmdir … ディレクトリ
というふうに、コマンドごとに補完対象を変えられるとさらに便利になる。complete コマンドを使うと、コマンドごとに補完対象をきめ細かく指定することができる。

以下に簡単な例をあげる。
% complete alias 'p/1/a/'
エイリアスのみを補完候補にする。ただし1番目の引数だけに対して効果がある。
% complete set 'p/1/s/'
シェル変数のみ。
% complete printenv 'p/*/e/'
環境変数のみ。何番目の引数でも効果あり。
% complete man 'p/*/c/'
コマンドのみ。何番目の引数でも効果あり。
% complete xdvi 'p/1/f:*.dvi/'
拡張子が .dvi であるファイルのみを補完候補にする。
% complete cc 'p/1/f:*.{c,cc}/'
拡張子が .c か .cc であるファイルのみを補完候補にする。

complete コマンドは、複雑で奥が深い。書式は
% complete コマンド名 '補完の種類/(マッチパターン or 引数番号)/補完対象/'
である。

まずは、'p/*/.../' という書き方を覚えよう。
`...' の部分に以下の文字を指定することで、補完候補を限定できる。
c コマンド
d ディレクトリ
f ファイル名
a エイリアス (alias コマンドで設定されているもの)
e 環境変数 (setenv コマンドで設定されているもの)
s シェル変数 (set コマンドで設定されているもの)
v 環境変数とシェル変数
u ユーザ名 (/etc/passwd に書かれているユーザ名)
g グループ名 (/etc/group に書かれているグループ名)
j ジョブ (jobs で表示されるジョブ)
l リミット (limit コマンド・ulimit コマンドで表示されるリミット名)
例をあげると、
% complete unalias 'p/*/a/'
補完対象はエイリアス
% complete unsetenv 'p/*/e/'
補完対象は環境変数
% complete foo 'p/*/es/'
補完対象は環境変数とシェル変数
また、その文字の後に : を付けると、シェルのワイルドカードが使える。
% complete foo 'p/*/f:*.txt/'
補完対象は *.txt にマッチするファイル
% complete foo 'p/*/u:a*/'
補完対象は a から始まるユーザ名

次に、'p/*/(... ... ...)/' という書き方。
例えば
% complete foo 'p/*/(abc def hij)/'
とすると、
% foo (TAB)
abc def hij
と、`()' で囲んだ文字列を補完候補にすることができる。

次に、'p/*/$xxx/' という書き方。
$xxx はシェル変数として扱われる。
% set xxx = (abc def hij)
% complete foo 'p/*/$xxx/'
と、
% complete foo 'p/*/(abc def hij)/'
は同じ意味である。ただし $xxx の内容を変更すると、補完対象も動的に変わる。よって、補完動作を行うときには必ず $xxx を設定しておかなくてはならない。

続いて、'p/*/`...`/' という書き方。
バッククォート `` で囲むことで、その中のコマンドを実行し、その結果を補完候補とする。例えば、talk コマンドの補完対象は現在ログイン中のユーザ名になってほしいので
% complete talk 'p/*/`users`/'
とする。これで、
% talk (Ctrl-D)
user1 user2
と、Ctrl-D や TAB を押すたびに users コマンドが実行され、ログイン中のユーザのみが補完対象となる。

次に、'c/XXX/YYY/' という書き方。
これは、「現在 XXX まで入力していたら、YYY を補完対象にする」という意味である。`YYY' の部分には、p/// の書き方のところで紹介した (... ... ...) ・ $xxx ・ `...` などの形式をそのまま使うことができる。
% complete foo 'c/abc/e/'
とすると、
% foo (Ctrl-D)
% foo a(Ctrl-D)
では、何も起こらない (デフォルト動作である、ファイル・ディレクトリの一覧を表示する)。しかし、abc とタイプした後に Ctrl-D を押すと
% foo abc(Ctrl-D)
CDPLAYER DISPLAY HOST LESS MPEGTABLES PWD USER
CVSEDITOR EDITOR HOSTDISPLAY LESSCHARSET OSTYPE SHELL VENDOR
と、環境変数の一覧を表示する。

% complete foo 'c/abc/(xx yy zz)/'
ならば、
% foo abc(Ctrl-D)
xx yy zz
となる。

特に、これはオプションを補完候補にする場合に有効である。例えば
% complete foo 'c/-/(x y z)/'
% foo -(Ctrl-D)
x y z
と、オプションの一覧を手軽に見ることができる (もちろん TAB で補完もできる)。さらに、`XXX' の部分には、メタキャラクタを使うことができる。
% complete foo 'c/-[abc]/(x y z)/'
% foo -a(Ctrl-D)
x y z
% foo -b(Ctrl-D)
x y z
この例では、-a か -b か -c が入力されると、x y z という補完候補を表示する。
% complete foo 'c/-A*/(x y z)/'
だと、-A から始まる文字列 ( -A や -Ab -Ac -Aabc など) が入力されているときは x y z が補完対象になるし、
% complete foo 'c/-*A/(x y z)/'
は、- から始まり A で終わる文字列 (-*A にマッチする文字列) が入力されているとき、x y z が補完対象になる。

最後に 'n/XXX/YYY/'。
これは 'c/XXX/YYY/' とほぼ同じであるが、違うのは `XXX' の次の引数に対して `YYY' を補完対象にすることである。
% complete foo 'c/XXX/(YYY)/'
だと、`XXX' の直後に TAB を押すと
% foo XXX(TAB)
YYY
となるが、
% complete foo 'n/XXX/(YYY)/'
% foo XXX(TAB)
と、`XXX' の直後に TAB を押しても何も起こらない。しかし
% foo XXX (TAB)
`XXX' の後に空白を入れて TAB を押すと `YYY' が補完対象となる。

再度、'p///' について補足説明。
実は p/// は、何番目の引数かによって、補完対象を限定する命令である。
% complete foo1 'p/1/c/'
補完対象はコマンド名。ただし1番目の引数のみ。
% complete foo2 'p/3/c/'
補完対象はコマンド名。ただし3番目の引数のみ。
% complete foo3 'p/*/c/'
補完対象はコマンド名。何番目の引数でも有効。
上記の例では、
% foo1 (Ctrl-D)
1番目の引数なので、コマンド名の一覧を表示
% foo1 foo (Ctrl-D)
2番目の引数に対しては設定されていないので、ファイル・ディレクトリの一覧を表示 (デフォルト動作)
% foo2 (Ctrl-D)
1番目の引数に対しては設定されていないので、ファイル・ディレクトリの一覧を表示 (デフォルト動作)
% foo2 foo bar (Ctrl-D)
3番目の引数なので、コマンド名の一覧を表示
となる。foo3 は何番目の引数であっても、常にコマンド名を表示する。

最後に、p/// c/// n/// の使い分けについて。
例えば find コマンドは、-type の後に f s b c l などの引数を書く。そういう場合、
% complete find 'n/-type/(f s b c l)/'
とする。一方、find の引数には -type の他にも、-name -size -inum -exec など多くの引数を取ることができる。この場合には
% complete find 'c/-/(type name size inum exec)/'
と、n/// でなく c/// を使うわけだ。一方 p/// は何番目の引数かを指定したいとき、例えば
% complete telnet 'p/1/(localhost host1 host2)/' 'p/2/(http ftp pop3)/'
などいうふうに使う。また、特に何番目の引数かを指定しない場合でも
% complete foo 'p/*/a/'
としてもよい。

さて、一通り説明をしたので実際に設定例をあげよう。まずは先程あげた簡単な例。
% complete alias 'p/1/a/'
% complete printenv 'p/*/e/'
% complete man 'p/*/c/'
% complete xdvi 'p/1/f:*.dvi/'
% complete cc 'p/1/f:*.{c,cc}/'
これらはもう説明はいらないだろう。

次に find コマンド。
find コマンドは -type -name -size などのオプションがあり、
'c/-/(type name size inum exec print)/'
-type の後には f s b c l などの引数を取る。
'n/-type/(f s b c l)/'
-user の後にはユーザ名、-group の後にはグループ名を取る。
'n/-user/u/' 'n/-group/g/'
また、find はディレクトリ名を受け取り、そこを起点にファイルシステムを検索するので、
'p/*/d/'
も指定しよう。これらの設定を反映させるには、全て繋げればよい。つまり
% complete find 'c/-/(type name size inum exec print)/' 'n/-type/(f s b c l)/' 'n/-user/u/' 'n/-group/g/' 'p/*/d/'
とすればよい。ここで大事なのは、'p/*/d/' を最後に持っていくことである。この設定では
% find -(Ctrl-D)
type name size inum exec print
となるが、もし 'p/*/d/' を先頭に持っていき
% complete find 'p/*/d/' 'c/-/(type name size inum exec print)/' ...
% find -(Ctrl-D)
とすると、tcsh は - がディレクトリの一部であると判断し、- から始まるディレクトリの一覧を表示する。もし - から始まるディレクトリが存在しなければ、何も表示しなくなる。狭い範囲の設定を先に (左に) 書き、広い範囲の設定は後に (右に) 書く、ということを覚えておこう。

次に talk コマンド。
talk の引数はユーザ名であるが、現在ログイン中のユーザ名だけを補完対象にしたい。
% finger | awk '{print $1}' | tail +2 | sort -u
で、現在ログインしているユーザ名だけをピックアップできるので、これを complete コマンドの中に組み込めばよい。

まずは先程の例から '' を外し、代わりに \ でエスケープする。
finger | awk \{print\ \$1\} | tail +2 | sort -u
これは、tcsh (sh・csh も同じ) では、'' の中に ' を含めることができないからである。perl と違って、'\'' としても、真ん中の ' はエスケープされない。'' の中では \ は \ そのものとして扱われるので、メタキャラクタをエスケープする能力を失ってしまうのである。今回は、最終的に
complete finger 'p/.../.../'
と、全体を '' で囲みたいので awk の部分で '' を使わないようにするのである。次に全体を `` (バッククォート) で囲む。
`finger | awk \{print\ \$1\} | tail +2 | sort -u`
さらに p/1// の中に入れる (1番目の引数が対象)。
p/1/`finger | awk \{print\ \$1\} | tail +2 | sort -u`/
全体を '' で囲む。
'p/1/`finger | awk \{print\ \$1\} | tail +2 | sort -u`/'
先頭に complete とコマンド名を付けて できあがり。
% complete talk 'p/1/`finger | awk \{print\ \$1\} | tail +2 | sort -u`/'

最後に telnet コマンド。
telnet コマンドは、
% telnet ホスト名
% telnet ホスト名 ポート番号 (あるいはポート名)
という引数を受ける。そこで、ホスト名とポート名を補完するようにしよう。ホスト名は
% set hosts=(foo.bar.com hoge.fuga.ac.jp)
と、シェル変数 $hosts で設定しておく。

また、ポート名は /etc/services から取得する。/etc/services の中身は
ポート名 ポート番号/プロトコル
という形式になっており、# はコメントを表すので、
% cat /etc/services | awk '{print $1}' | sed 's/#.*//' | sort -u
でプロトコルの一覧を得られる。ただしこれでは問題がある。FreeBSD の /etc/services には
sql*net 66/tcp #Oracle SQL*NET
という行が含まれているのだが、このように * や ? が含まれていると、補完動作をしたとき (Ctrl-D や TAB を押したとき) に、tcsh が * や ? をワイルドカードとみなして、パターンマッチを行おうとする。そこで
% cat /etc/services | awk '{print $1}' | sed 's/#.*//' | sort -u | sed 's/\*/\\*/g'
と、`*' を `\*' に置換しなければならない。

あとはこれをひとつにまとめればよいのだが、先に述べたように、まず '' を含まない形に変更すると
% cat /etc/services | awk \{print\ \$1\} | sed s/#.\*// | sort -u | sed s/\\\*/\\\\\*/g
となる。あとは、1番目の引数ならホスト名を、2番目の引数ならポート名を補完させればよい。ただし、sed の引数に `/' を渡しているので、`p///' という形式は使えない。代わりに`p@@@' や `p^^^' という書き方ができる。最終的には
% set hosts=(foo.bar.com hoge.fuga.ac.jp)
% complete telnet 'p/1/$hosts/' 'p@2@`cat /etc/services | awk \{print\ \$1\} | sed s/#.\*// | sort -u | sed s/\\\*/\\\\\*/g`@'
となる。長いね…。

ここでコマンド補完の設定にも触れておこう。tc と入力して補完しようとすると、
% tc (Ctrl-D)
tcsh tconv tclsh tcpdump tcpslice
と、tc から始まるコマンドの一覧が表示される。もしこの中で tcpdump だけを補完対象としたければ、
% complete -tc* 'p/0/(tcpdump)/'
とする。p/0// の 0 は 0 番目の引数、つまりコマンド自身を表している。すると、
% tc (Ctrl-D)
tcpdump
となり、tcpdump 以外のコマンドが補完候補から外される。

なお、シェル変数 fignore で指定したファイル群は補完対象から外される。
>> Cシェル変数 fignore *
>> コマンド uncomplete *

compress ファイルを圧縮する

圧縮ファイル名は元ファイル名の最後に .Z を付けたもの。昔はよく使われていたが、今はより圧縮率の高い gzip があるので、特に理由がないなら gzip を使う方がよい。

ただし一部の商用 UNIX では gzip コマンドが標準で入っていないため、泣く泣く compress を使うことはよくある。また、圧縮率が悪い分動作は速いので、目的に応じて使い分けよう。

-c 圧縮結果を標準出力に書き出す。ファイル操作は行なわれない。
-f 圧縮ファイルが元ファイルより大きくなっても強制的に圧縮ファイルを作る
-v 圧縮率を表示

% ls -l file.txt
-rw-r--r-- 1 zxr400 zxr400 34473 Oct 26 21:36 file.txt
% compress file.txt
⇒ file.txt を圧縮する。
% ls -l func.html.Z
-rw-r--r-- 1 zxr400 zxr400 14796 Oct 26 21:36 file.txt.Z
⇒ file.txt は削除され、file.txt.Z が生成される。ファイルサイズは 40% ほどになった。
% ls -l file.txt
-rw-r--r-- 1 zxr400 zxr400 34473 Oct 26 21:36 file.txt

% compress -c file.txt > file.txt.Z
⇒ 元の file.txt を残しておきたい場合は -c を使うとよい
>> コマンド uncompress *   gzip *   bzip2 *

configure Makefile 生成スクリプト

make コマンドは、書き方次第でいろいろなプラットフォームに対応できるが、それでも限界がある。そこで、コンパイルする前に関数やライブラリなどの有無をチェックし、どのような環境でもコンパイルを可能にしようという目的で、autoconf や automake というソフトウェアが作成された。autoconf を使うと、configure という sh スクリプトを作成することができる。これを配布したいパッケージの中に含めておく。

アプリケーションをインストールしたい利用者は、アーカイブを展開して
% ./configure
として configure というスクリプトを実行すればよい。各種システムコールやライブラリなどが揃っているかどうかを自動的にチェックして、適切な Makefile を生成してくれる。その後は
% make
でコンパイル、su して root になり、
# make install
でインストールである。

configure は
% ./configure --enable-hoge
% ./configure --prefix=/foo/bar
などとオプションを指定することができるが、どのようなオプションがあるかはアプリケーションごとに大きく違う。オプションの一覧は
% ./configure --help
で見ることができる。

一般的に、一度 configure を実行した後に配布時の状態に戻したい場合は
% make distclean
とすると実行ファイル・オブジェクトファイル・Makefile などが消去される。
>> コマンド make *   xmkmf *

convert 画像ファイルを変換する (ImageMagick)

どのフォーマットに変換するかは、指定した拡張子から自動的に判別してくれる。
% convert sample.gif sample.jpg
⇒ GIF 形式の sample.gif から JPEG 形式の sample.jpg に変換する

また、adjoin オプションで、動画 GIF を生成することができる。
% convert -adjoin image01.gif image02.gif image03.gif sample.gif
⇒ image01〜03.gif からなる、動画 GIF sample.gif を生成する
その逆はこれ。
% convert +adjoin sample.gif image%02d.gif
⇒ 動画 GIF sample.gif を分割し、image00,01,02...gif という画像ファイルを生成する
>> コマンド display *   identify *   ImageMagick *   xv *   gs *

cp ファイルをコピーする

ファイルをコピーする。
% cp sample1.dat sample2.dat
⇒ sample1.dat を sample2.datにコピー
% cp sample1.dat sample2.dat sample3.dat dir/
⇒ sample1.dat・sample2.dat・sample3.dat をディレクトリ dir の下にコピー

なお、DOS とは違って UNIX では メタキャラクタの展開はシェルの役割なので、
% cp *.txt *.txt.bak
などと、拡張子を変更したファイルのコピーはできない。この場合、csh・tcsh なら foreach、sh・bash なら for を使うとよい。
>> コマンド foreach *   for *

オプション
-i コピー先のファイルが存在する場合、上書きしてよいか確認を求める。
操作に慣れていないうちは、
alias cp "cp -i" (csh・tcsh の場合)
alias cp="cp -i" (sh・bash の場合)
を設定しておくとよい。
>> コマンド alias *
-f 上書き確認を行わない。これはデフォルトだが、alias cp cp -i としている場合に便利
-p タイムスタンプもそのままコピーする
-R ディレクトリを再帰的にコピーする
ディレクトリ dir1 以下に、ファイル foo・bar があった場合、
% cp -R dir1 dir2
は、ディレクトリ dir2 の下にディレクトリ dir1 をコピーする。つまり
  • dir2/dir1/foo
  • dir2/dir1/bar
というファイルが新たに作成される。一方、
% cp -R dir1/ dir2
とすると (`/'を付けると)、dir2 の下に dir1 以下のファイル・ディレクトリをコピーする。つまり
  • dir2/foo
  • dir2/bar
というファイルができる。
>> コマンド mv *   rcp *
>> 読み方 cp *

cpp C プリプロセッサ

C のソースを解析し、#define、#include、#ifdef、sizeof などの処理を行う。通常 C コンパイラから自動的に呼ばれる。

一般的なプリプロセッサが解釈できるマクロや条件式を以下に紹介する。

#define
マクロを定義する。いくつか使い方があるが、まずは数値の定義から。
#define BUFLEN 256
#define PERSON_MAX 10
char buf[BUFLEN];
for ( i=0 ; i<PERSON_MAX ; i++ ) ...
#define M_PI 3.14159265358979323846

関数の別名定義。
#define MYFUNC0 hoge
#define MYFUNC1(x) hoge(x)
#define MYFUNC2(x,y) hoge(x,y)
#define MYFUNC3(x) hoge(x,(x)+1)
MYFUNC3 のように引数で受けた値を複数回使用する場合は注意。もし MYFUNC3(a++) とすると hoge(a++, (a++)+1) と展開されてしまう。

条件判断。
#define IS_HOGE(x) (0 < (x) && (x) < 256)
if ( IS_HOGE(i) ) ...
if ( IS_HOGE(i+1) ) ...

複数の実行文 (マルチステートメント) をまとめる。
#define MYFUNC(x, y) do { func(x); func(y); } while(0) /* ここにセミコロンを付けないこと */
一見、do 〜 while ループを取り去って
#define MYFUNC(x, y) { func(x); func(y); }
としてもよいように思えるが、これだと
if (hoge)
MYFUNC(1,2);
else
printf("hoge");
としたときに文法エラーとなってしまう。

#ifdef の使用を前提とした #define。以下の例でデバッグモードにしたくないときは、#define DEBUG_MODE の行をコメント化すればよい
#define DEBUG_MODE
#ifdef DEBUG_MODE
fprintf(stderr, "foo=%d\n", foo);
#endif

多重 include を避けるための #define。同じインクルードファイルを何度も include してしまい、マクロ再定義などの警告が発生することがある。しかしファイルの数が多くて依存関係が複雑なとき、一度しか include しないようにするのは至難の技だ。そういうときは以下のように、何度 include されても初回しか評価されないようにすればよい。
#ifndef _FOO_H_
#define _FOO_H_
#define FOO_NUM 100
void foo_func(char *);
#endif
一回目は _FOO_H_ が定義されていないので #ifndef _FOO_H_ は偽になり、内部が評価される (そしてこのとき _FOO_H_ が定義される)。二回目以降は #ifndef _FOO_H_ が真になるため、内部はスキップされる。これは stdio.h などの標準のヘッダファイルでも広く使われている有名な技である。

なお、型の別名定義のために #define を使うと問題が発生することがある。
#define MYCHAR char
MYCHAR c;
⇒ これは問題ない (char c と置換される)
#define MYCHAR_P char *
MYCHAR_P p;
⇒ これも問題ない (char *p と置換される)
#define MYCHAR_P char *
MYCHAR_P p1,p2;
⇒ これはダメ (char *p1,p2 となってしまう。おそらく意図したのは char *p1,*p2 だろう)
型の別名は typedef を使うこと。
typedef char *MYCHAR_P;
MYCHAR_P p1,p2;
⇒ typedef を使えば OK (char *p1,*p2 と解釈される)
構造体にいちいち「struct」を付けないための typedef もよく使われる。
typedef struct {
int member1;
char *member2;
} hoge_t;
なお、定義した型には size_t・time_t・pid_t などにならって、末尾に「_t」(type の略) を付けることをお勧めする。

#if・#ifdef
バージョンによる切り分け。
#if __FreeBSD_version >= 500000

#elif __FreeBSD_version >= 400000

#else

#endif

複雑な形の #ifdef。
#if defined(__FreeBSD__) && !defined(__NetBSD__)

#endif
もし #if を使わないなら、以下のように読みづらい形になってしまう。
#ifdef __FreeBSD__
#ifndef __NetBSD__

#endif
#endif
どうしてもこのようにネストせざるをえない場合は、以下のように #endif の後にコメントを付けるとよい。
#ifdef __FreeBSD__
#ifndef __NetBSD__

#endif /* __NetBSD__ */
#endif /* __FreeBSD__ */

コメントアウト目的の #if。コメント化したい場所に /* 〜 */ というコメントが含まれている場合、/* 〜 */ で囲ってしまうとコメントがネストしてしまいエラーとなる。そのような場合は #if 0 〜 #endif で囲むとよい。なお、#if 〜 #endif はネストできるので、さらに外側に #if 0 〜 #endif を重ねてもよい。
#if 0
func1(); /* 処理 A */
func2(); /* 処理 B */
func3(); /* 処理 C */
#endif

#include
ヘッダファイルを取り込む (include する)。
#include <stdio.h>
⇒ システム標準のディレクトリ (/usr/include) から先に検索
#include "hoge.h"
⇒ カレントディレクトリ先に検索し、見つからなければシステム標準のディレクトリを探す

#error
強制的に処理を打ち切り、エラーとする。例えば FreeBSD の /usr/include/varargs.h には以下のようにある。
#if defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ > 2 || __GNUC__ >= 4)
#error "<varargs.h> is obsolete with this version of GCC."
#error "Change your code to use <stdarg.h> instead."
#endif
⇒ gcc-3.3 以上か gcc-4 以上で varargs.h をインクルードしている場合はエラーとし、「varargs.h でなく stdarg.h を使用してね」というメッセージを表示する
gcc-3.3.3 で #include <varargs.h> を含むソースをコンパイルすると、以下のようにエラーになる。
% gcc foo.c
In file included from foo.c:1:
/usr/include/varargs.h:34:2: #error "<varargs.h> is obsolete with this version of GCC."
/usr/include/varargs.h:35:2: #error "Change your code to use <stdarg.h> instead."

定義済マクロ
ANSI C (ISO C) では以下の定義済マクロを用意している。
main(){
printf("__FILE__: %s\n", __FILE__);
printf("__LINE__: %d\n", __LINE__);
printf("__DATE__: %s\n", __DATE__);
printf("__TIME__: %s\n", __TIME__);
printf("__STDC__: %d\n", __STDC__);
printf("buf=%s\n", buf);
}
実行結果は以下の通り。
% ./a.out
__FILE__: foo.c
⇒ ソースファイル名 (cc hoge/foo.c としてコンパイルしたら __FILE__ は hoge/foo.c となる)
__LINE__: 4
⇒ ソースの行番号 (__LINE__ が置かれた場所の行番号)
__DATE__: Aug 1 2004
⇒ コンパイルを行った年月日
__TIME__: 03:43:21
⇒ コンパイルを行った時分秒
__STDC__: 1
⇒ ANSI C 準拠の環境なら 1

典型的な使い方は、エラーが発生したファイルと行番号を表示するものである。
ret = func();
if ( ! ret ){
fprintf(stderr, "%s:%d func error\n", __FILE__, __LINE__);
exit(1);
}

より洗練されたやり方は以下の通り。エラーチェックの場所に毎回 __FILE__ や __LINE__ を書く必要がない。__FILE__ や __LINE__ は #define の場所でなく、ERROR マクロを使用している場所を示す。
#define ERROR(str) fprintf(stderr, "%s:%d " str "\n", __FILE__, __LINE__);
ret = func();
if ( ! ret ){
ERROR("func error");
exit(1);
}

さらによいのは可変引数関数と可変個数引数のマクロを使った以下のやり方であろう。ERROR マクロに可変個数の引数を渡すことができ、詳細なエラー情報を出力できるからである。
#include <stdio.h>
#include <stdarg.h>
#define ERROR(fmt, ...) error(__FILE__, __LINE__, fmt, __VA_ARGS__)
void error(char *file, int line, char *fmt, ...){
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d ", file, line);
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
va_end(ap);
}
main(){
ret = func(str);
if ( ! ret ){
ERROR("func error. ret[%d] str[%s]", ret, str);
exit(1);
}
}
なお、#define での可変個数引数 (... と __VA_ARGS__) は 1999年に成立した C99 という規格で定められたものだが、規格制定前に先行して実装していたコンパイラも多い。お手元の環境で使用可能かどうか一度試してみるとよいだろう。

その他の定義済マクロを表示するには、GNU cpp ならば -dM オプションを使う。
% cpp -dM /dev/null
#define __FreeBSD__ 3
#define __FreeBSD_cc_version 330001
#define i386 1
#define __GNUC__ 2
#define unix 1
(略)
とする。ソースファイルとして /dev/null を指定しているので、処理系独自のマクロのみが表示される。

この他に言語独立なプリプロセッサとしては以下のものがある。
  • mcpp
C/C++ 対応。ソースが C90・C99 などの各規格に合致しているか検証する機能があるため、移植性の高い記述が可能。作者が日本人なので日本語ドキュメントが用意されている。ちなみに「未踏ソフトウェア採択プロジェクト」である。
  • filepp
基本的なプリプロセッサの機能に加え、ループ機能などの独自拡張を施している。
  • chaos-pp
使ったことがないので、何とも言えず。
>> コマンド gcc *   filepp *   cc *   unifdef *

cron スケジューラデーモン。クーロン。

cron は OS 起動時に自動的に起動され、デーモンとして OS に常駐している。
% ps ax | grep '[ c]ron' (SysV系なら ps -ef)
118 ?? Ss 0:00.03 cron
cron は1分に一度
  • /etc/crontab に書かれているプログラム。例えば /etc/daily・/etc/weekly、ログファイルを更新する newsyslog コマンド、at コマンドで登録したプログラムを実行する atrun などは /etc/daily・/etc/weekly から実行される。
  • 一般ユーザが crontab コマンドで登録したプログラム
を調べ、そこに書かれている通りにコマンドを実行する。

一般ユーザに crontab を使わせたくないならば、/usr/bin/crontab のパーミッションを
# chmod 4550 /usr/bin/crontab
としておくとよい。

cron の設定ファイルについては crontab コマンドを参照。
>> コマンド crontab *   at *
>> 設定ファイル /etc/crontab *
>> 読み方 cron *

crontab スケジュールを登録。決められた時刻にプログラムを実行する。クーロン。

定期的に実行するコマンドを管理する。

日時を指定して、自動的にコマンドを実行することができる。設定方法は FreeBSD なら
% crontab 設定ファイル名
とし、Solaris なら
% echo '分 時間 日 月 曜日 コマンド名' | crontab
% crontab < 設定ファイル名
のどちらでもいい。当ページ管理人は、~/.crontab というファイルを作り、このファイルをエディタで編集してから、
% crontab ~/.crontab
として cron に反映する方法を好む。ただし、この方法だと cron に登録されているデータと ~/.crontab の内容が一致している保証はない、という欠点がある (crontab -e で直接編集しないように気をつける必要がある)。

オプション
  • -l 現在設定されている crontab データを表示する
  • -r 現在設定されている crontab データを解除する。

cron を設定した後は、必ず crontab -l で確認すること。もし動作がおかしいなら crontab -r で設定をクリアできるが、その後も必ず crontab -l で確認しよう。

設定ファイル書式
設定ファイルの書式は
分 時間 日 月 曜日 コマンド名
である。例を以下に示す。
* * * * * command
⇒ 1分おきに command を実行する。
10 3 1 * * command
⇒ 毎月1日の3時10分に command を実行する。
0 12 * * 0 command
⇒ 毎週日曜日の12時に command を実行する。

実行結果はメールで自分自身に知らされる。メールを送ってほしくない場合は、
* * * * * command 1> /dev/null
と標準出力を捨てればよい。この場合はエラーが起こった時だけ (標準エラー出力に出力があった時だけ)メールが送られてくるので便利である。エラーが起ころうと絶対にメールを送ってほしくない場合は
* * * * * command >/dev/null 2>&1
とすればよい。
>> 用語集 リダイレクト *

なお、crontab で実行されるときには、ほとんどの環境変数が設定されていないので注意が必要。~/.cshrc・~/.login で設定している環境変数は設定されていないし、PATH も /bin:/usr/bin くらいにしか通っていない。そのため、command の部分に指定するのはシェルスクリプトにしておいて、シェルスクリプトの先頭で環境変数の設定を行い、その後いろいろなコマンドを実行するようにしておくのがよいだろう。

Tips.1
メールは ISO-2022-JP (いわゆる JIS コード) で送るというきまりがあるので、出力が EUC-JP や Shift_JIS などの日本語を含む場合は、
* * * * * command | nkf -j
と、nkf などで ISO-2022-JP に変換すればよい。
>> コマンド nkf *   qkc *   euctosj *   iconv *

Tips.2
cron の設定ファイルでは、
* * * * * cd foo/bar; command
というふうに、セミコロンで区切ることで複数のコマンドを記述することができる。その他にもシェルが解釈できる構文や * ? などのメタキャラクタも使用可能である。これは cron は書かれた行をそのままシェルに渡すからである。標準のシェルは sh なので、sh が解釈できるものは何でも書けるというわけだ。

ただし、設定ファイルの先頭で
SHELL=/bin/csh
などと書くと、sh でなく csh に渡されることになり、
* * * * * command >& /dev/null
といった csh 風の書き方ができるようになる (FOO=bar という変数の設定は、少なくとも FreeBSD では可能。他の OS ではダメかもしれない)。

Tips.3
cron では、1分より細かい単位で実行することはできない。もし 30秒ごとにコマンドを実行したい場合は
* * * * * date & sleep 30 ; date
などと書けばよい。
Tips.4
前処理のプログラムが正常終了した場合のみ、次のプログラムを実行したい場合は、
* * * * * command1 && command2
とする。
前処理プログラム A と B を並列実行し、A・B 両方が終了したらプログラム C を実行するには
* * * * * (commandA & commandB & wait) && commandC
とする。

商用システムでこのような複雑な制御を行いたい場合は、日立の JP1 というジョブ管理製品を使うプロジェクトが多いようだ。しかし使いづらいので、当ページ管理人は JP1 は嫌いである。

cron の欠点
cron の欠点は以下の通り。
  • 1分単位でしか起動できない。例えば n 秒おきに起動、ということができない (できなくはないが、Tips3 のように小細工が必要になる)。
  • 登録した時刻にマシンが起動していないと、永遠に起動されない。
  • 指定した日が祝日なら、次の営業日に実行、というちょっと凝った指定ができない。
  • 重複起動防止の機能はない。プログラムを毎分実行するように設定したとして、もしプログラムの実行に 1分以上かかってしまっても、新たにプロセスがどんどん生成される。重複起動を避けたい場合は、個々のプログラムで排他制御をする必要がある。
  • Tips.4 のように、cron にて前処理・後処理を行うことは可能だが、「前処理のプログラムが異常終了した場合に手動リカバリ後にその次のプログラムから再開」といった賢いリカバリ作業はできない。
>> コマンド at *   cron *
>> 設定ファイル /etc/crontab *
>> 読み方 cron *

crypt 暗号化・復号化ツール

暗号化キーを与えることで、ファイルを暗号化することができる。もちろん暗号化するときに使ったキーを知らないと復号化できない。FreeBSD の場合、米国の暗号輸出規制の影響か(どうかはわからないが)、crypt がない。代わりに bdes コマンドがある。
>> コマンド bdes *   openssl *

csh Cシェル

C言語のような文法を持つシェル。とはいえC言語ができるからといってすぐ使えるというわけではない。ユーザインターフェイス機能が弱いので、ログインシェルとしては より高機能な tcsh や bash を使う方がよいだろう。ログインシェルを変更するには、chsh コマンドを使う。
>> コマンド chsh *

なお、FreeBSD では 4.1-RELEASE から tcsh がデフォルトでインストールされるようになり、csh が tcsh へのハードリンクとなった。

また、スクリプトを書く際は、csh・tcsh の機能が貧弱なことから、sh・bash の方を使うことが多い。
-f ~/.cshrc を読まずに起動する。
シェルスクリプトの1行目で #!/bin/csh -f というのをよく見かけるが、その場合ユーザ独自の ~/.cshrc は読まれないので、エイリアスやシェル変数は使用できなくなる。
-n 文法のチェックだけを行なう。シェルスクリプトのチェックに使われる
-s 標準入力からコマンドを読み込む
-v 実行文を表示。スクリプトのデバッグ時に使われる
-x 実行文を表示。スクリプトのデバッグ時に使われる
>> 用語集 リダイレクト *   シェルスクリプト *
>> コマンド bash *   sh *   tcsh *
>> 読み方 csh *

ctags 

cu モデムのチェック。

本来はシリアル接続されている機器とやりとりするためのコマンドだろうが、よくわからない。

cut テキストを切り出す(パイプ)

各行から「n 文字目から m 文字目」「n 番目から m 番目からのカラム」というようなルールで文字列を切り出す。

バイト数で指定
-b[num1]-[num2] num1 バイト目からnum2 バイト目までを切り出す
% cut -b30 < file.txt
⇒ file.txt の30バイト目を切り出す
% cut -b20-30 < file.txt
⇒ file.txt の20バイト目から30バイト目までを切り出す
% cut -b-30 < file.txt
⇒ file.txt の行頭から30バイト目までを切り出す
% cut -b20- < file.txt
⇒ file.txt の20バイト目以降を切り出す
文字数で指定
-c[num1]-[num2] num1 文字目からnum2 文字目までを切り出す
バイト単位で切り出す -b オプションと同様の動作をするが、正しくロケールを認識する Solaris などでは日本語としての文字数を指定できる。
% cat file-euc.txt
あいうえお
% env LC_ALL=ja_JP.eucJP cut -c3-4 < file-euc.txt
うえ
⇒ 日本語として解釈し、3〜4文字目を切り出す
% cut -b3-4 < file-euc.txt

⇒ バイト単位だと 3〜4バイト目として扱われる
フィールド数で指定
-f フィールド番号 指定したフィールドを出力する。デフォルトのフィールド区切りは TAB である。
% cat file.txt
abc(TAB)def(TAB)ghi(TAB)(TAB)jkl
% cut -f 1 < file.txt
abc
⇒ 1番目のフィールドを表示
% cut -f 2,3 < file.txt
abc def
⇒ 2番目と 3番目のフィールドを表示
% cut -f 2- < file.txt
def ghi jkl
⇒ 2番目以降のフィールドを表示
-d str フィールドを区切る文字として文字列 str を使用する。
-d オプションを使う場合は -f オプションを同時に指定しないと意味がない。
% cat file.txt
abc,def,ghi,,jkl
% cut -d , -f 2,3 < file.txt
def,ghi
⇒ カンマ区切りとみなして 2番目と 3番目のフィールドを表示
>> コマンド head *   tail *   awk *   sed *

CVSチュートリアル基礎編 バージョン管理ツール (基礎編)

CVS はファイルのバージョン管理を行うツールである。FreeBSD・NetBSD・OpenBSD・ Apache・Darwin などの数多くのオープンソースプロジェクトが CVS を採用している。ちなみに当ページのコンテンツは CVS を用いて管理している。

利点
CVS を使うことの利点は以下のとおり。
ファイルの変更履歴を記録できる。
⇒ 古いバージョンに戻すことができる。
⇒ ファイルの修正中に、どの部分をどう修正したかを確認できる。
正確なリリース作業が行える。
⇒ ファイルを転送し忘れた、古いファイルをリリースしてしまった、ということがない
複数人での作業ができる。
⇒ 複数人でひとつのファイルを編集できる。

用語
まずは以下の用語を覚えてほしい。
リポジトリ
ファイルの保管庫。ファイル内容と、過去の修正履歴が格納されている。リポジトリの実体はただのテキストファイルであるが、これを直接修正することはまずない。「レポジトリ」と表記する人もたまにいる。
チェックアウト
リポジトリからファイルを取り出すこと。チェックアウトした後は、ファイルを眺めたり、ファイルを修正したりする。
コミット
チェックアウトしたファイルを修正した後に、リポジトリへ反映すること。
リビジョン
ファイルごとに振られる版数のこと。初期登録時は 1.1 で、コミットを重ねるたびに、1.2・1.3・1.4 … 1.99・1.100・1.101 … と上がっていく。

書式
CVS に関する操作を行うには cvs コマンドを使用する。cvs コマンドの書式は
% cvs [共通オプション] [サブコマンド] [サブコマンドオプション] [サブコマンド引数]
である。サブコマンドとは init・checkout・diff・commit などがあり、サブコマンドが異なるとサブコマンドオプションやサブコマンド引数の意味が異なる (CVS のマニュアルでは init・checkout などをコマンドと命名しているが、ここではあえてサブコマンドと表記している)。

共通オプションとサブコマンドオプションは全く異なるものである。例えば
% cvs -d /home/68user/cvsroot checkout -d source project-a
は -d が 2つあるが、意味は全然違う。最初の -d は共通オプションで、リポジトリの場所を指定している。2つ目の -d はサブコマンド checkout のサブコマンドオプションで、チェックアウト先のディレクトリを指定するオプションである。

リポジトリ初期化 (init)
リポジトリの初期化には cvs init コマンドを使用する。まず、リポジトリを置く場所を決めよう。当ページ管理人の場合は、/home/68user/cvsroot/ というディレクトリをリポジトリ置き場としている。あらかじめディレクトリを作成する必要はなく、いきなり cvs init すればよい。なお、リポジトリの場所は (相対パスではなく) フルパスで指定すること。
% cvs -d /home/68user/cvsroot init
これにより、以下のファイル・ディレクトリが自動的に生成される。
/home/68user/cvsroot/
/home/68user/cvsroot/CVSROOT
/home/68user/cvsroot/CVSROOT/Emptydir
/home/68user/cvsroot/CVSROOT/loginfo
/home/68user/cvsroot/CVSROOT/loginfo,v
/home/68user/cvsroot/CVSROOT/rcsinfo
/home/68user/cvsroot/CVSROOT/rcsinfo,v
/home/68user/cvsroot/CVSROOT/editinfo
/home/68user/cvsroot/CVSROOT/editinfo,v
(略)
cvsroot/ の下には CVSROOT/ というディレクトリが作成されているが、これはリポジトリ設定用のファイルなので、とりあえずは気にしなくてよい。

今後 cvs コマンドを使うたびにリポジトリの場所を共通オプション -d で指定するのは面倒なので、環境変数 CVSROOT に設定しておこう。これで共通オプション -d は不要になる。
% setenv CVSROOT /home/68user/cvsroot (csh・tcsh の場合)
% CVSROOT=/home/68user/cvsroot; export CVSROOT (sh・bash の場合)

インポート (import)
リポジトリを作成したら、管理したいファイルを cvs import でインポートする。もしとりあえず CVS を試してみたいだけなら、以下のサンプルプログラムを使うとよい。

ファイル・ディレクトリ構成
  • hello/
  • hello/hello.c
  • hello/Makefile
hello/hello.c
#include 
main(){
    printf("Hello, world.\n");
    return 0;
}
hello/Makefile
TARGET=hello
OBJS=hello.o
$(TARGET): $(OBJS)

上記のファイル群を用意したら、インポート前に行う下準備は 2つ。
  • モジュール名を決める
  • 不要なファイルを消す
モジュール名とは、最上位のディレクトリ名のことを指す。ここでは hello としておこう。そして CVS で管理したくない不要なファイルを削除する。この例では、make すると生成される実行ファイル hello、オブジェクトファイル hello.o、エディタのバックアップファイル hello.c~ などは管理対象としない方がよい。そのため、インポート前に不要なファイルを削除しておこう。

準備ができたら、cvs import でインポートする。書式は以下の通り。
% cvs import [モジュール名] [ベンダタグ] [リリースタグ]
ベンダブランチ・イニシャルブランチはとりあえずは気にせず、それぞれ vendor・initial としておこう。必ずカレントディレクトリを hello/ に変更してからインポートすること。
% cd hello/
% cvs import -m "Initial version" hello vendor inital
U hello/hello.c
U hello/Makefile

No conflicts created by this import

「No conflicts created by this import」と表示されれば正常にインポートできたということである。インポートが完了したら、リポジトリ内にどのように格納されているのか確認しておこう。
% find ~/cvsroot/hello
/home/68user/cvsroot/hello
/home/68user/cvsroot/hello/hello.c,v
/home/68user/cvsroot/hello/Makefile,v
ディレクトリ名はそのままだが、ファイル名の末尾には「,v」が付加されている。これが CVS が管理しているファイルの印である。

チェックアウト
リポジトリ内のファイルを取得したり編集したりするには、まずチェックアウトを行わなければならない。まず、CVS の作業場所を決めておこう。ここでは ~/work/ とする。~/work/ に移動して
% cvs checkout [モジュール名]
とすることでチェックアウトが行える。
% mkdir ~/work
% cd ~/work
% cvs checkout hello
cvs checkout: Updating hello
U hello/Makefile
U hello/hello.c
チェックアウトしたディレクトリのファイル構成を確認しよう。
% find hello/ -print
hello/
hello/CVS
hello/CVS/Root
hello/CVS/Repository
hello/CVS/Entries
hello/Makefile
hello/hello.c
チェックアウトしたディレクトリ内には、必ず「CVS」というディレクトリが作成され、その下には Root・Repository・Entiries というファイルがある。各ファイルの内容は以下の通りである。
hello/CVS/Root … リポジトリの場所
/home/68user/cvsroot/
hello/CVS/Repository … この作業場所が対応するリポジトリ内のディレクトリのパス
hello
hello/CVS/Entries … この作業場所で管理しているファイル・ディレクトリ
/Makefile/1.1.1.1/Sun Jul 24 06:54:10 2005//
/hello/1.1.1.1/Sun Jul 24 06:54:10 2005//
/hello.c/1.1.1.1/Sun Jul 24 06:54:10 2005//
これらは CVS 管理用ファイルなので削除してはならないし、内容を改編してはならない。

差分表示 (diff)
チェックアウトしたファイルは、エディタなどを使って自由に修正してよい。

修正中は cvs diff を使って、どの部分を修正したのかを確認しよう。以下は hello.c をエディタで修正した後に cvs diff で差分を表示する例である。
% cvs diff
RCS file: /home/68user/cvsroot/hello/hello.c,v
retrieving revision 1.1.1.1
diff -r1.1.1.1 hello.c
3,4c3,4
< main(){
<     printf("Hello, world.\n");
---
> main(int argc, char *argv[]){
>     printf("This is a sample program of cvs\n");
当ページ管理人は声を大にしていいたいのだが、CVS が威力を発揮するのはここである。エディタの操作ミスやなどで意図せぬ修正を行ってしまった場合でも、cvs diff を行うことでミスに気づくことができる。また、テストのために一時的に変更した行の戻し忘れもここで見付けられる。コミット前には必ず cvs diff を使うようにしよう。

cvs diff には多くのオプションが指定できるが、ほとんどは diff コマンドと共通である。最低限、-u で Unified Diff 形式の差分表示ができることを覚えておくとよい。
% cvs diff -u
RCS file: /home/68user/cvsroot/hello/hello.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 hello.c
--- hello.c     24 Jul 2005 06:54:10 -0000      1.1.1.1
+++ hello.c     25 Jul 2005 13:58:08 -0000
@@ -1,5 +1,5 @@
 #include <stdio.h>

-main(){
-    printf("Hello, world.\n");
+main(int argc, char *argv[]){
+    printf("This is a sample program of cvs\n");
 }
>> コマンド diff *

コミット (commit)
ファイルの修正が完了したら、コミットを行ってリポジトリに反映する。
% cvs commit hello.c
とすると vi や Emacs などのエディタが起動するので、コミットログの入力を行う。
■ (←カーソル位置)
CVS: ----------------------------------------------------------------------
CVS: Enter Log. Lines beginning with `CVS:' are removed automatically
CVS:
CVS: Committing in .
CVS:
CVS: Modified Files:
CVS: hello.c
CVS: ----------------------------------------------------------------------
以下のように修正理由や修正概要を記入する。
hoge 値の自動補正機能は今回の開発で削除する予定だったが、
これを削除すると fuga 値に影響が及ぶことが発覚したため、
削除を取り止める (仕様変更)。
CVS: ----------------------------------------------------------------------
CVS: Enter Log. Lines beginning with `CVS:' are removed automatically
(以下略)
「CVS:」から始まる行は無視されるので、そのまま残しておけばよい (削除してもよいが、意味がない)。記入したら内容を保存してエディタを終了する (vi なら :wq、Emacs なら C-x C-s C-x C-c)。すると、
Checking in hello.c;
/home/68user/cvsroot/hello/hello.c,v <-- hello.c
new revision: 1.2; previous revision: 1.1
done
というふうにコミットが行われる。hello/hello.c のリビジョンが 1.1 から 1.2 に上がったことがわかる。コミット時に使用するエディタは、環境変数 EDITOR や環境変数 CVSEDITOR で指定が可能である。
>> 環境変数 EDITOR *

もし cvs commit してエディタが起動した後にコミットをやめたくなった場合は、コミットログ内容を空にして保存し、エディタを終了する。すると
Log message unchanged or not specified
a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
Action: (continue)
と、「ログメッセージが指定されていないがどうする?」と聞いてくる。ここで a (abort) をタイプすればコミットされない。もし e (edit) とすれば再度エディタが起動し、c (continue) とすれば「*** empty log message ***」というログでコミットが実行される。

いちいちエディタが起動するのが面倒ならば、
% cvs commit -m 'コミットメッセージ'
と、サブコマンド commit の -m オプションでコマンドラインからコミットログを指定することもできる。

一度コミットした後にコミットログを変更するには、サブコマンド admin に -m オプションを付けることで可能である。
% cvs admin -m1.4:"ほげほげ" hello.c
⇒ hello.c のリビジョン 1.4 のコミットログを「ほげほげ」に変更

ファイル追加
ファイルを追加するには cvs add を使用する。
% cd hello
% echo hoge > newfile.txt
⇒ 適当なファイルを新規作成
% cvs add newfile.txt
cvs add: scheduling file `newfile.txt' for addition
cvs add: use 'cvs commit' to add this file permanently
⇒ 「newfile.txt を追加予定ファイルとして登録した。ほんとに追加したいなら cvs commit してね」と言っている。
cvs add しただけではまだリポジトリにはファイルが追加されていない。確認のため、cvs status で状態を確認しよう (cvs status 自体の説明は後述)。
% cvs status newfile.txt
===================================================================
File: newfile.txt       Status: Locally Added (★注目)

   Working revision:    New file!
   Repository revision: No revision control file
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)
「Status: Locally Added」となっているので、手元の作業場所に追加予定ファイルとして登録されただけで、リポジトリには反映されていないことがわかる。cvs commit でコミットを行うと、リポジトリに反映される (cvs commit すると例のごとくエディタが起動するので、コミットログを記入すればよい)。

cvs add した後に、ファイル追加を取り止めたくなった場合は
% rm newfile.txt
⇒ まずファイル自体を削除 (一時的に mv で別のファイル名に変えてもよい)
% cvs remove newfile.txt
⇒ cvs remove で追加予定ファイル一覧から除外する
とする。ファイル自体を削除したくなければ、一時的に mv で別のファイル名に変えておけばよい。

なお、バイナリファイルの場合は cvs add に -kb オプションを付けること。
% cvs add -kb newimage.jpg
-kb についての詳細は CVS トピック編を参照のこと。
>> コマンド CVSトピック編 *

ファイル削除
一度リポジトリに追加したファイルの削除は、cvs remove で行える。
% cd hello
% rm newfile.txt
⇒ まずファイル自体を削除 (一時的に mv で別のファイル名に変えてもよい)
% cvs remove newfile.txt
cvs remove: scheduling `newfile.txt' for removal
cvs remove: use 'cvs commit' to remove this file permanently
⇒ 削除予定ファイル一覧に追加された
この段階ではまだリポジトリに反映されていない。cvs add と同様に、コミットすることで実際にファイルは削除される。なお、ファイル削除といっても修正履歴は全て残るし、いつでもファイルは復活できる。実際に行われることは、リポジトリに「Attic」というディレクトリが作成され、そこに移動されるだけである。
% find ~/cvsroot/hello
/home/68user/cvsroot/hello
/home/68user/cvsroot/hello/Attic (★ここ)
/home/68user/cvsroot/hello/Attic/newfile.txt (★ここ)
/home/68user/cvsroot/hello/hello.c,v
/home/68user/cvsroot/hello/Makefile,v

cvs remove で削除したファイルを元に戻すには、cvs add すればよい。まず、復活させたい newfile.txt を用意する。削除した時点と同じファイルでもよいし、内容を変えたければ変えてもよい。例えば newfile.txt の履歴が
  • リビジョン 1.1 … 新規作成
  • リビジョン 1.2 … 内容修正
  • リビジョン 1.3 … 削除
となっている場合は、
% cd hello
% cvs update -p -r 1.2 newfile.txt > newfile.txt
とするとリビジョン 1.2 の newfile.txt が入手できる。ファイルが用意できたら cvs add する。
% cvs add newfile.txt
cvs add: re-adding file newfile.txt (in place of dead revision 1.2)
cvs add: use 'cvs commit' to add this file permanently
⇒ 復活予定ファイル一覧に追加された
後はコミットすれば元通りになる。

ディレクトリ追加
ディレクトリの追加は、ファイル追加と同様に cvs add を使用する。
% cd hello
% mkdir newdir
⇒ 適当なディレクトリを作成
% cvs add newdir
Directory /home/68user/cvsroot/hello/newdir added to the repository
ファイル追加の場合は cvs add・cvs commit という二段階を踏む必要があったが、ディレクトリの追加は cvs add すると即座にリポジトリに反映されることに注意しよう。

ディレクトリ削除
一度 add したディレクトリを削除することは、できない。良く言えば「仕様」、悪く言えば「CVS の欠点」である。ただし、リポジトリを直接いじるという裏技はある。上記の newdir ディレクトリ追加の例では、
/home/68user/cvsroot/hello/newdir/
というディレクトリが作成されているので、これを直接 rmdir すればよい。ただし、そのディレクトリを既にチェックアウトした人がいたら、エラーとなる。また、newdir/ の下に既にファイルを追加していた場合は、そのファイルの履歴は全て消えてしまう。当ページ管理人が直接リポジトリのディレクトリを rmdir するのは、以下の条件を全て満たすときである。
  • そのディレクトリを誰もチェックアウトしていない
  • 削除したいディレクトリの下にファイルを置いたことがない

状態表示 (status)
作業場所のファイルの状態を表示するには cvs status を使う。
% cvs status
===================================================================
File: Makefile          Status: Up-to-date

   Working revision:    1.1.1.1 Sun Jul 24 06:54:10 2005
   Repository revision: 1.1.1.1 /home/68user/cvsroot/hello/Makefile,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)

===================================================================
File: hello.c           Status: Locally Modified

   Working revision:    1.5     Sat Jul 30 14:26:13 2005
   Repository revision: 1.5     /home/68user/cvsroot/hello/hello.c,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)
Makefile がリビジョン 1.1.1.1、hello.c が 1.5 であり、Makefile は最新版 (Up-to-date)、hello.c は修正されているがまだコミットされていない (Locally Modified) ことがわかる。

一人で、ひとつの作業場所で作業する場合は、以下のステータスを覚えておけばよい。
Up-to-date 最新版。リポジトリの最新リビジョンと内容が完全に一致している状態
Locally Added ファイルを cvs add したが、まだコミットしていない状態
Locally Removed ファイルを cvs remove したが、まだコミットしていない状態
Locally Modified 作業場所のファイルを修正したが、まだコミットしていない状態
全てのステータスや、Sitcky Tag・Sticky Date・Sticky Options については CVS トピック編を参照。

CVSチュートリアル応用編へ続く。
>> コマンド CVSチュートリアル応用編 *   CVSトピック編 *   CVS運用編 *

CVSチュートリアル応用編 複数人での開発・タグ・ブランチ

複数人での開発
CVS は一人だけで使ってもそれなりに便利であるが、複数人による開発でこそ実力を発揮する。

サンプルは基礎編に引続き hello モジュールとする。ファイル構成は以下のとおり。
hello/
hello/Makefile (リビジョン 1.1 とする)
hello/hello.c (リビジョン 1.1 とする)
まず作業場所を 2つ作ろう。workA/ と workB/ はそれぞれ A さんと B さんの作業場所と仮定する。
% mkdir workA workB
% (cd workA; cvs checkout hello)
% (cd workB; cvs checkout hello)
CVS は、基本的にはロックという概念がないため、複数人が同時にチェックアウトすることができる。一方、Microsoft のバージョン管理ツール VSS (Visual Source Safe) では、チェックアウトしたファイルはロックがかかり、他の人は同じファイルをチェックアウトすることができなくなる。

まず、A さんが workA のファイルを修正し、コミットしたとする。
Aさん% cd workA/hello/
Aさん% vi hello.c
⇒ A さんが workA/hello/hello.c を編集した
Aさん% cvs commit hello.c
⇒ コミット
ここで workA/hello/hello.c はリビジョン 1.2 にあがるが、workB/hello/hello.c はリビジョン 1.1 のままである。ファイルがコミットされたからといって、他の人がチェックアウトしたファイルが勝手に更新されるようなことはない。

B さんが workB の状態を確認したとする。
Bさん% cd workB/hello/
Bさん% cvs status
===================================================================
File: hello.c           Status: Needs Patch

   Working revision:    1.1     Sat Jul 30 14:26:13 2005
   Repository revision: 1.2     /home/68user/cvsroot/hello/hello.c,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)
ステータスが「Needs Patch」となっているので、手元のファイルが古いことがわかる。また、「Working revision」「Repository revision」により、手元の作業領域の hello.c はリビジョン 1.1 であるが、リポジトリの hello.c はリビジョン 1.2 に更新されたことがわかる。

いつ・誰が・なぜ更新したかは cvs log で確認できる。
Bさん% cvs log hello.c
Working file: hello.c
head: 1.2
----------------------------
revision 1.2
date: 2005/07/30 20:23:30;  author: Aさん;  state: Exp;  lines: +2 -2
メッセージが気にいらないので修正。
B さんが、A さんが行った修正をとりいれたい場合は、cvs update を使う。
Bさん% cvs update hello.c
U hello.c
これで最新版に更新された。念のため cvs status を実行して、ステータスが「Up-to-date」になっていることを確認しよう。

マージと衝突 (コンフリクト)
未稿。

タグ
未稿。

ブランチ
未稿。
>> コマンド CVSチュートリアル基礎編 *   CVSトピック編 *   CVS運用編 *

CVSトピック編 CVS に関するいろいろな情報

本項は、CVS の使用方法をひととおりマスターした人向けの説明である。CVS の使い方そのものがわからない場合は、まずチュートリアルをどうぞ。
>> コマンド CVSチュートリアル基礎編 *   CVSチュートリアル応用編 *

CVS のマニュアルでは init・checkout などをコマンドと命名しているが、ここではあえてサブコマンドと表記する。

リビジョン番号
リビジョン番号は 1.1 からスタートして、1.2・1.3・1.4 … 1.99・1.100・1.101 … と上がっていく。たまに
「メジャーバージョンが上がったら 2.0 にしたい」
と言う人がいるが、これはやめた方がよい。普通は 1.xx のままにしておいて、このような管理はタグで行う。タグであれば後から削除することもできるが、リビジョンを 2.0 にあげてしまえばもう元に戻すことができない。例えば「リリース直前に障害多発のためリリースは延期」となってももうリビジョンは元に戻せない。

さらに言えば、リビジョンはただのファイルごとの通番である。一方、メジャーバージョンというのは、そのファイルが社会の中でどのような位置づけにあるか (正式版なのか、テスト版なのか) という概念である。まわりの状況が変われば、この位置づけも容易に変わるものである (先にあげたリリース延期など)。このようなあやふやな概念を、通番とリンクさせるのは得策ではない。タグという緩いつながりで結ぶことで、変化に柔軟に対応しやすくしておくわけである。ちなみに当ページ管理人は、有名なオープンソースのプロジェクトで 2.x とか 3.x などとリビジョンを上げているものを見たことがない。

どうしてもやりたければ、コミットの際に
% cvs commit -r 2.0
とすることで実現できるが、ファイルが修正されていない場合はコミットできないため (プロジェクト全体のメジャーバージョンは上がっても、全ファイルに修正が入るとは限らない)、$Id を修正したり、適当な場所に空白を入れたりして無理矢理コミットすることになる 。その結果、実質的にはファイル内容に変化がないのに、リビジョン 2.0・3.0・4.0 ができてしまう、ということになる。

さらに、
「メジャーバージョン.マイナーバージョン.バグFIXバージョン.メッセージ等修正バージョンとしたい」
などという人がいるが、これもやめた方がよい。というより、CVS ではたぶんできないような気がする (リビジョン番号はブランチ管理も兼ねているため)。

状態一覧
cvs status で表示される状態の一覧を以下に示す。
Up-to-date 最新版。リポジトリの最新リビジョンと内容が完全に一致している状態
Locally Modified 作業場所のファイルを修正したが、まだコミットしていない状態
Locally Added ファイルを cvs add したが、まだコミットしていない状態
Locally Removed ファイルを cvs remove したが、まだコミットしていない状態
Needs Checkout 自分以外の誰かが新たなファイルを追加したが、手元の作業場所ではまた cvs update していない状態。あるいはチェックアウトしたファイルを rm で消した状態。
Needs Patch 自分以外の誰かがコミットしたものの、手元の作業場所は cvs update していないため、手元のファイルが古い状態
Needs Merge
Unresolved Conflict 複数人が名前が同じファイルを cvs add して片方がコミットした場合、もう片方ではこの状態になる。誰がどのファイルを追加するかの認識にずれがある。コミュニケーションを密にとろう。
File had conflicts on merge CVS によるマージの際に、衝突 (コンフリクト) が発生した。ファイルの衝突部分を修正してコミットすればよい。
Unknown 不明なファイル。cvs status [存在しないファイル] などとした状態
Entry Invalid 誰かが作業場所で cvs remove してコミットを行った後に、別の作業場所で同じファイルを rm で削除した、など

複数アカウントでの利用
ひとつのアカウントで CVS を利用している場合は何ら問題ないが、複数のアカウントで CVS を利用する場合は、リポジトリの所有者とパーミッションが問題となる。

リポジトリがローカルに置いてあるとき、CVS を操作するということは結局はリポジトリのファイルを読み込んだり、変更したりしているわけである。もし userA と userB という 2つのアカウントから操作をする場合は、いずれのアカウントからもリポジトリのファイルに対して read・write 権限を与えなければならない。

当ページ管理人がよくやる方法は以下の通りである。まず、cvs というグループを作成し、そこにリポジトリにアクセスできるアカウントを追加する。例えば /etc/group に
cvs:*:3000:userA,userB
と記述する。追加後は id コマンドを実行して、cvs グループに加わっていることを確認しよう。
% id
uid=1001(userA) gid=101(userA) groups=0(wheel), 3000(cvs)
そしてリポジトリのグループを cvs に変更し、グループに対する write 権限を与える。
(ここでの $CVSROOT は CVS リポジトリの場所を表す)
% chgrp -R cvs $CVSROOT
% chmod -R g+w $CVSROOT
これで userA と userB の両方が、全ファイルを修正できるようになった。さらに Solaris などの SystemV 系 UNIX では、ディレクトリに対して setgid ビットを立てておく。
% find $CVSROOT -type d | xargs chmod g+s

setgid ビットを立てる理由を説明する。CVS で新規ファイルを add した場合の挙動を考えよう。userA と userB のグループが以下のとおりであるとする。
  • userA のプライマリグループ: groupA、その他のグループ: cvs
  • userB のプライマリグループ: groupB、その他のグループ: cvs
そして以下のように、ディレクトリ dir/ のグループが cvs、パーミッションが 775 だとしよう。
drwxrwxr-x   2 userA     cvs      117  7月 31日  19:20 dir/
ここで userB が dir/ の下に新たなファイル・ディレクトリを作成したとき、新規ファイルのグループはどうなるだろうか。これは OS によって結果が異なる (CVS に特化した話ではなく、UNIX 一般の話である)。
●BSD 系 UNIX の場合
drwxrwxr-x   2 userB     cvs      100  7月 31日  19:25 dir/newfile.txt
⇒ 上位ディレクトリ (dir/) のグループ cvs を引き継ぐ
●SystemV 系 UNIX の場合 drwxrwxr-x 2 userB groupB 100 7月 31日 19:25 dir/newfile.txt
⇒ 作成者 (userB) のプライマリグループ groupB がセットされる
CVS を利用する上で好ましいのは BSD 系 UNIX の方である。なぜなら、新規ファイルのグループが cvs となるため、userB が追加した dir/newfile.txt を userA が編集することができるからだ。一方、SystemV 系 UNIX の場合は、userB が作成したファイルを修正できるのは userB だけになってしまう。

ただし SystemV 系 UNIX でも BSD と同様の挙動をさせる方法がある。それがディレクトリに対して setgid ビットを立てる方法である。このビットを立てておくと、BSD と同様に新規ファイル・ディレクトリの作成時に上位ディレクトリのグループを引き継ぐようになる。setgid ビットが立っているかどうかは、パーミッションが「drwrsx」となっていることで確認できる。
% ls -ld dir
drwxrsxr-x   2 userA     cvs      117  7月 31日  19:20 dir/

ちなみに Linux ではデフォルトは SystemV 系 UNIX と同じ動作をするが (setgid についても同様)、mount のオプションで BSD と同じ挙動をさせることができる。
>> 設定ファイル /etc/group *
>> コマンド chmod *   chgrp *

rsh・ssh・pserver
未稿。

日時
CVS では日時を UTC (いわゆるグリニッジ標準時) で管理している。cvs log や cvs status で表示される日時は UTC である。ところが cvs checkout・cvs diff・cvs update などのサブコマンドオプション -D は、ローカルタイムとして扱われる。

以下、タイムゾーンが JST であると仮定する。
% date
Sun Jul 31 02:57:08 JST 2005
⇒ date コマンドでタイムゾーンが JST となっている
cvs log の結果が以下のようになっていたとする。
% cvs log file.txt
----------------------------
revision 1.3
date: 2005/07/30 10:00:00; author: 68user; state: Exp; lines: +1 -0
修正その 2
----------------------------
revision 1.2
date: 2005/07/30 05:00:00; author: 68user; state: Exp; lines: +1 -1
修正その 1
----------------------------
revision 1.1
date: 2005/07/30 00:00:00; author: 68user; state: Exp; lines: +1 -1
初期バージョン
このときリビジョン 1.3 のコミット時刻は「2005/07/30 10:00:00」となっている。しかしリビジョン 1.3 と比較するつもりで
% cvs diff -D "2005/07/30 10:00:00" file.txt
と -D オプションで日時を指定した場合は JST として解釈されてしまい、UTC の 2005/07/30 01:00:00 として扱われる。その結果、リビジョン 1.3 ではなく、リビジョン 1.1 と比較することになってしまう。

CVS の出力は UTC だが、ユーザの入力はローカルタイムとして扱われるというわかりにくい仕様で、なおかつ JST や UTC などのタイムゾーンが一切表示されないため、勘違いしやすい。これは CVS のひどい欠陥である。当ページ管理人の結論としては「日時に頼るな、タグを使え」である。

なお、日時表記を JST などに統一する方法は存在しない (少なくとも cvs-1.11.5 では)。「タイムゾーンをまたがる開発をする場合は UTC じゃないと困る」と言う人もいるが、当ページ管理人がこれまで CVS を利用した環境は、全て JST であった。ちなみに cvsweb では設定ファイルにてタイムゾーンを設定できて便利である。

エンコーディングの統一
ファイルとコミットログのエンコーディング (文字コード) は統一しておこう。もしファイルが Shift_JIS・コミットログが EUC-JP などとエンコーディングが混在していた場合は、CVS 的には何ら問題はないが、扱う人間にとっては管理しづらくなる。

当ページでは全てファイルのエンコーディングは EUC-JP にしている。また、コミット時に起動するエディタ (emacs) のエンコーディングも EUC-JP としているため、コミットログも EUC-JP となる。

サブコマンドの別名
CVS はサブコマンドが長いので、いちいち cvs checktout や cvs update とタイプするのは結構ダルい。そういう人のために短めの別名が定義されている。
サブコマンド 別名 (短縮系)
add ad または new
admin adm または rcs
annotate ann または blame
checkout co または get
commit ci または com
diff di または dif
export exp または ex
history hi または his
import im または imp
log lo
login logon または lgn
rannotate rann または ra
rdiff patch または pa
release re または rel
remove rm または delete
rlog rl
rtag rt または rfreeze
status st または stat
tag ta または freeze
update up または upd
version ve または ver
別名の数は多いが、当ページ管理人が使うのは cvs co・cvs up・cvs di くらいである。この一覧は cvs --help-synonyms で確認できる。これでも我慢できない人は、tcsh の complete コマンドでがんばって補完の定義をしよう。
>> コマンド complete *

ヘルプ
全体のオプションを表示
% cvs --help
共通オプション一覧を表示
% cvs --help-options
サブコマンド一覧を表示
% cvs --help-commands
サブコマンドの短縮形一覧を表示
% cvs --help-synonyms
サブコマンドの書式 (サブコマンドオプションとサブコマンド引数) を表示
% cvs [サブコマンド] --help

ヘルプオプション自体にも短縮形があり、上記のヘルプはそれぞれ
% cvs --h
% cvs --help-o
% cvs --help-c
% cvs --help-s
% cvs [サブコマンド] -h
としてもよい。

キーワード置換
未稿。

バイナリファイル
CVS はバイナリファイルの扱いがちょっと苦手である。なぜなら、バイナリファイル中にたまたま $Id や $Log などのキーワードが入っていた場合、キーワード置換が行われるからである。ほとんどの画像ファイルなどは、$Id と同じコードが含まれていることはまずないので、よほど運が悪くなければ本当にキーワード置換が行われることはない。

しかし念のため「このファイルはバイナリファイルなのでキーワード置換はしないこと」というマークを付けておこう。cvs add の際に -kb オプションを付けることでバイナリファイルのマークが付けられる。
% cvs add -kb newimage.jpg
このマークは、cvs status で確認できる。
% cvs status newimage.jpg
File: newimage.jpg      Status: Up-to-date

   Working revision:    1.1     Sun Jul 31 09:01:31 2005
      Repository revision: 1.1     /home/68user/cvsroot/hello/newimage.jpg,v
      Sticky Tag:          (none)
      Sticky Date:         (none)
      Sticky Options:      -kb (★ここ)
cvs add 時に -kb を付け忘れてコミットしてしまった場合は、後から cvs admin で -kb を追加できる。
% cvs admin -kb newimage.png
RCS file: /home/68user/cvsroot/hello/newimage.png,v
done
admin -kb で修正されるのはリポジトリ側だけなので、手元のファイルはまだキーワード置換が行われたファイルである (もしキーワードが含まれていれば)。ステータスが「Needs Checkout」になるので、
% cvs update newimage.png
としてキーワード置換を抑止したファイルを取得しなおすこと。キーワード置換は、コミット時に行われるのではなく、ファイル取得時 (checkout・update) に行われるので、これで正しいファイルを取得できる。

とはいえ、ファイルを追加する際に -kb を付けるのではいつかミスが起きそうである。そこで CVSROOT/cvswrappers に「この拡張子はバイナリファイル」と記述しておけば、勝手にバイナリファイルとしてキーワード置換が抑止される。
% cd work (適当な作業場所に移動)
% cvs checkout CVSROOT
cvs checkout: Updating CVSROOT
U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/editinfo
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg
% cd CVSROOT
として、cvswrappers に以下の行を追加する。
*.gif -k 'b'
*.jpg -k 'b'
*.png -k 'b'
最後にコミットを忘れずに。
% cvs commit -m '*.{gif,jpg,png} はキーワード置換を抑止' cvswrappers

リポジトリのコピー
未稿 (repocoy した後はタグを外すのを忘れずに)。

リポジトリの移動
未稿。

ファイルを古いバージョンに戻す
未稿 (ロールバック的なことはできない。古いファイルを持ってきてコミットすること)。

CVS の補助ツールたち
cvsweb
cvsweb は、web 上から CVS リポジトリを閲覧するツール (CGI プログラム) である。あくまで閲覧ができるだけで、web 上からコミットなどの操作は行えない。cvsweb にはいろいろなバージョンがあるが、当ページ管理人は以下のように認識している。
  • Fenner 氏が最初に cvsweb を開発した
  • Zella 氏が改良した (annotate 機能・色付き diff など)
  • knu 氏が Zella 氏に機能改善のパッチを送ったが全く採用してくれないので、fork して knu-cvsweb を作った
  • その結果、Zella-cvsweb と knu-cvsweb が並行して開発されていた
  • knu-cvsweb は FreeBSD-cvsweb に名称変更 (FreeBSD-cvsweb 2.0 からスタート)
  • Zella-cvsweb は実質的に開発停止
  • 現在は knu 氏は FreeBSD-cvsweb から手を引き、FreeBSD CVSWeb Project が開発を続けている。FreeBSD-cvsweb 3.0 あたりが最新版

当ページで使用している cvsweb
は knu-cvsweb-1.105.1.65 である (knu-cvsweb の 1.65 で、fork 時点から Zella-cvsweb-1.105 までの機能をとり入れたもの)。

cvsweb.cgi と cvsweb.conf を置いて適当に修正すれば動く。当ページ管理人が修正した部分は以下のとおり (メッセージの日本語化も含む)。
修正理由も書いたので、適当に拾っていってほしい。
なお、cvsweb はローカルにリポジトリがないと動作しない (rsh・ssh・pserver 経由ではアクセスできない)。リポジトリと同じマシンで cvsweb を動かすか、定期的にリポジトリをコピーする仕組みを作ること。

ちなみに同種の web インタフェースとして ViewCVS というのもある。cvsweb との機能的な差違はほとんどないと思われるが、cvsweb は Perl で、ViewCVS は Python で記述されているところが大きな違いだろうか。

cvsgraph
web 上でリポジトリの分岐状況などをグラフ表示するツール。ブランチを導入していないならあまり意味がない。また、開発期間が長くなると画像が大きくなりすぎていまいち見づらい。
perl スクリプトなので、GD モジュールを適当にインストールすれば動く。cvsweb からリンクを張りたい場合は、FreeBSD-cvsweb 3.0 あたりなら cvsweb.conf の設定変更で OK。

SandWeb
cvsweb や ViewCVS はリポジトリを閲覧するだけだが、SandWeb は web 上から cvs のすべての操作を行うことができる。ただし、使いものになるかどうかは知らない (使ったことがない)。SandWeb は Cvswebclient の後継プロジェクトのようだ。
>> コマンド CVSチュートリアル基礎編 *   CVSチュートリアル応用編 *   CVS運用編 *

CVS運用編 CVS をお仕事なプロジェクトに導入するには

手作業でリリース管理を行っているプロジェクトに、CVS を導入する際のノウハウについて説明する。なお、当ページ管理人は業務系な人間なので、少々内容に偏りがあると思われる。CVS 自体の説明は、チュートリアル編を参照のこと。
>> コマンド CVSチュートリアル基礎編 *   CVSチュートリアル応用編 *

世の中には驚くほど後進的なプロジェクトがたくさん存在するものである。
  • ソースのマスタがない
  • 開発環境と商用環境でソースに差違がある (マスタもないので、どちらが正しいかわからない)
  • 過去のソースが保存されていない (潜在バグが発覚したとき、このバグはいつから存在したのか答えられない)
  • 誰が修正したのかわからない
  • 商用環境などへのリリース作業は修正したファイルを手作業で拾いだし、ファイルをひとつずつ FTP で転送する
運悪くこのようなプロジェクトに関わってしまった場合は、CVS を導入してまともなプロジェクトに変えていこう。

問題提起
大抵のプロジェクトでは、開発環境と商用環境が分かれているだろう。まずは開発環境と商用環境のソースを diff コマンドを使って比較してみよう。開発環境のソースを手作業で商用環境にリリースしているようなプロジェクトでは、まず間違いなくソースに差違が発生しているだろう。差違を見つけたら、「これは問題だ」「CVS で管理することで解決できる」とアピールしよう。

もしソースの差違が全くなかった場合は、ソース管理者が非常に優秀ということである。その場合は稼働工数削減を狙いにする。例えばソース管理者が 1人いて、修正したい場合は以下のような手順を踏んでいるとする。
  • ソース開放依頼書 (Excel シート) に修正対象ソース名・修正理由・修正者・日付を記述する。
  • ソース管理者がソース開放依頼書を確認し、最新ソースを修正者に送付
  • 修正者がソースを修正し、ソース管理者に送付
  • ソース管理者は修正版ソースをマスタに格納
1回あたり何分くらいかかって、1ヵ月で何時間の無駄が発生しているか計算し、「CVS なら質を落とさずに稼働を削減できます」とアピールしよう。

リポジトリ作成
まずはリポジトリにインポートするソースを決めなければならない。開発環境と商用環境から取得したソースで、差違があるものをリストアップし、どちらが正しいかを決定する。また、どれが必要なファイルで、どれが不要なファイルかを選別する。

ローカルルール策定
CVS を使用する上でのプロジェクト内のローカルルールを策定する。最低限、以下のことを明記しておくこと。
作業場所
最も望ましいのはメンバ全員のアカウントを作成し、
/home/member1/work/src/
/home/member2/work/src/
/home/member3/work/src/
/home/member4/work/src/
などと各メンバのホームディレクトリの下にソースをチェックアウトして、開発作業を行う方法である。もし「プログラムを動かすには必ず /home/proj/ の下にファイルを置く必要がある」などの場合は、いちいちコミットしないと動作確認ができないため作業効率が低下してしまう。このようなときは妥協案として
/home/proj/src/
の下を共有の作業場所としてもよい。

担当割の明確化
あるソースを修正する担当者は必ず 1人にしよう。できれば、以下のようにディレクトリ単位で担当者を決めておき、全員に周知しておくこと。
/home/proj/src/program1/ … A さん
/home/proj/src/program2/ … B さん
/home/proj/src/program3/ … C さん
CVS は複数人での作業が可能であるものの、複数人で同じソースを修正すること自体がミスの元である。できるだけひとつの機能を担当するのはひとりだけにしよう。

cvs diff での確認
コミット前に必ず cvs diff で修正点を確認するよう徹底させよう。エディタの操作ミスによる意図せぬ修正や、テスト用コードの戻し忘れがないかを確認できる。また、Windows 上のエディタでソースを作成して ffftp などで UNIX マシンに転送している場合におこりがちな以下のミスにも気づくことができる。
  • エディタのタブ設定の違いにより、全ての行のタブがスペースに変換されてしまった
  • FTP 転送時にアスキーモードとバイナリモードを間違え、改行コード CR+LF のまま UNIX マシンに転送してしまった
  • 「半角カナ→全角カナ」変換の機能を使用してしまい、ソース中の半角カナが全て全角カナに変わってしまった。
くどいようだが、これを全メンバに徹底すればかなりのコーディングミスは削減できる。cvs diff は面倒な作業ではなく、つまらないミスを事前に発見できる便利な機能であることを宣伝しよう。

コミットのタイミング
未稿 (ソースのコンパイルあるいは動作確認を確認してからコミットすること、など)。

コミットログ
コミットの際に入力するログ (メッセージ) の記述内容。修正理由は必須。できれば修正概要も記述する。もし修正概要を記入しなくても、後からソースの diff を見れば修正点は把握できる。しかし修正理由はソースを見てもわからないので、修正理由の方が優先度が高い。
例1. hoge 値の自動補正機能は今回の開発で削除する予定だったが、これを削除すると fuga 値に影響が及ぶことが発覚したため、削除を取り止める (仕様変更)。
⇒ 修正理由が書いてあるのがよい。
例2: hoge フラグが 1 の場合は fuga フラグを 2 にセットするよう修正。
⇒ 修正概要は書いてあるものの、なぜこの修正を行ったかがわからない。
例3: bugid:4432 対応
⇒ 別途バグ管理をしているなら、一意に特定できる管理番号を記述するだけでもよい。
CVS は誰がコミットしたかが記録されるようになっているが、全メンバが同じアカウントを使用していたり、他サーバにリポジトリを置いて、rsh や ssh を経由してコミットする場合に同じアカウントでログインしている場合は、修正者が全て同じになってしまう。このようなときは、ちょっと面倒だがコミットログに修正者を明記しよう。
例: 〜のため修正 by 68user

マニュアル作成
CVS を利用する上でのマニュアルを作成する。「web 見ろ」「man 読め」と言いたいのをぐっとこらえて、誰でも理解できる親切なマニュアルを作成しよう。
  • ファイルを追加するには
  • ファイルを削除するには
  • 修正点を確認するには
  • コミットするには
  • コミットしたファイルを元に戻すには
  • ディレクトリを作成するには
  • ディレクトリを削除するには
  • 古いコミットログを修正するには
といった HowTo 的な項目をずらっと並べる。プロジェクトメンバの技術レベルが低ければ低いほど、より力を入れて作成しよう。さらにローカルルールの説明も盛りこんでおく。なお、環境変数 CVSROOT が云々というような余計なことは書かないこと。まずは使い方の説明に徹する。「よくわからないから CVS は使わない」というセリフは言わせてはならない。

ビルド構成
大抵は、そのプロジェクトにおけるおおまかなディレクトリ構成が決められているだろう。たとえば
/home/proj/src/ … ソース置き場。この下で make する。
/home/proj/bin/ … 実行ファイル置き場。src/ で make すると bin/ に実行ファイルが置かれる。
/home/proj/lib/ … 設定ファイル置き場。
/home/proj/data/ … プログラムにより生成されるデータファイル置き場 (CSV ファイルなど)。
などである。この場合、CVS 管理を行うのは src/ と lib/ だけでよい。

ソース置き場は時間が経つと必ず汚れていく。テスト目的でソースを一時的に修正して、元に戻さずに忘れてしまったり、誤ってファイルを削除してしまうことがあるからだ。このような汚れたソース置き場で make したところで、正しい実行ファイルが生成されるはずがない。そこでソース置き場は自動的に削除し、最新ソースをチェックアウトすることをお勧めする。この作業は cron などに登録しておいて毎日行うとよい。作業の邪魔にならないよう、深夜や早朝に実施するのがよいだろう。

信頼できないソース置き場で make した場合は、当然ながら bin/ や lib/ も信頼できない。できれば bin/ や lib/ も毎日削除してしまおう。src/ で make したときに、bin/ や lib/ は自動的に mkdir するような Makefile を用意しておく。bin/ や lib/ のゴミ掃除にもなり、一石二鳥だ。

リポジトリのバックアップ
リポジトリはとても大事な資源である。毎日バックアップを取得しておこう。RAID 環境であっても、バックアップは必須である。「誤ってたくさんのファイルをコミットしてしまった」というときなどは、ファイルをひとつずつ元に戻してコミットしなおすよりも、昨日バックアップしたリポジトリに戻したことが早くて正確である。バックアップを行うには、リポジトリを tar と gzip で固めて、
repository-backup-YYYYMMDD.tar.gz
といったファイル名を付けておけばよい。ディスクに余裕があるなら何年分でも保存しておけばよいが、もし直近 50 日分だけ保存しておきたい場合は
% ls -r repository-backup-*.tar.gz | tail +51 | xargs rm
などと 51 個目以降を削除すればよい。

コミットメール
コミットしたときにメーリングリスト宛に以下のようなメールを飛ばすことをお勧めする。
Subject: CVS: proj/src/program1/src committed by 68user.

Update of proj/src/program1/src
In directory hostname:/tmp/cvs-serv28826/proj/src/program1/src

Modified Files:
    program1.c
Log Message:
エラー発生時のログ出力の情報を充実化。

Index: prohello.c
===================================================================
RCS file: /home/cvsroot/proj/src/program1/src/program1.c

retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- program1.c   12 Jul 2004 07:41:24 -0000    1.4
+++ program1.c   28 Jul 2005 07:30:55 -0000    1.5
@@ -80,7 +80,7 @@
    if ( is_error ){
-      log_error("○○処理が異常終了");
+      log_error("○○処理が異常終了 [顧客コード:%d] [物品コード:%d]",
+                customer_code, item_code);
    }
このメーリングリストには開発者メンバ全員が参加する。狙いは以下の通り。
  • どのソースにどういう修正を行ったかを全員に知らせる
  • 修正内容がおかしい場合は、すぐに突っ込む
  • 他メンバの作業内容に興味を持たせる
  • 自分の作業内容がメンバ全員に知られることを意識させる (汚いソース・コピペの抑止)

ただしメンバ全員がメールを熟読することを本気で期待しないこと。他人の仕事に無関心な人は必ずいる。コミットメールをソースレビューの代わりにしようなどと思わず、メールでミスに気づいたらラッキー程度に考えるとよい。ただし誰かひとり、できればあなたは時間がある限りコミットメールをざっと眺めて、たまに適度な突っ込みを入れ、ちゃんと見てるんだぞとアピールしよう。

上記の仕組みを実現するには http://radiofly.to/nishi/cvsbook/ で配布されているスクリプト mailto-committers.pl を使用するとよい (ちなみにこのページで紹介されている本は、CVS 関連の本の中でもっともおすすめである)。

設定方法は以下の通り。
CVSROOT をチェックアウト。
% cd work (適当な作業場所に移動)
% cvs checkout CVSROOT
mailto-committers.pl を用意し、CVSROOT/mailto-committers.pl として追加。
% cd CVSROOT
% cvs add mailto-committers.pl
どこかから jcode.pl を拾ってきて、CVSROOT/jcode.pl として追加。
% cvs add jcode.pl
CVSROOT/checkoutlist に以下の 2行を追加。
mailto-committers.pl
jcode.pl
CVSROOT/loginfo に以下の行を追加 (cvslog@example.co.jp はメーリングリスト)。
DEFAULT $CVSROOT/CVSROOT/mailto-committers.pl %{sVv} $USER cvslog@example.co.jp
上記の修正を全てコミット。
% cvs commit

タグ
商用リリース時には PHASE99_RELEASE などのタグを付加すること。もし開発工程が厳密に分かれているなら、結合テストリリース時には PHASE99_IT_RELEASE タグを付加、というふうにしてもよい。また、商用環境でバグが出たら、修正ソースに PHASE99_BUGFIX007 などとタグを付けるのもアリだろう。

タグを打っておくと「このタグを打った時点から現時点までに修正したソース一覧を表示」といった調査が簡単に行える。しかしタグを打ちすぎるとウザくなる。どういうイベントでタグを打つかは事前に決めておこう。ただしタグを後から削除することもできるし、過去の特定の日時の時点でのソースにタグを打つこともできる。

タグを打つ際は、そのとき修正したソースだけにタグを打つのではなく、モジュール以下の全ファイルにタグを打つことをお勧めする。全ファイルにタグを打っておけば「このタグを打った時点での全ソースを取得」などということが簡単にできるからである。その結果、修正が行われなかったファイルについては、同一リビジョンに複数のタグが打たれることになるが、これは全く問題ない。

なお、各メンバが個別にタグを打つのではなく、ソース管理者が一括してタグを打つとよい。その際は、「いまからタグを打つが、まだコミットしていないソースがあれば教えてほしい」と確認を取ること。

リリース作業
開発環境とネットワーク的に接続されていない環境、たとえば商用環境へのリリース作業について説明する。

まず、できれば商用環境にも CVS をインストールしておこう。そして以下のような手順を推奨する。
  • 開発環境で cvs diff して、コミット忘れがないことを確認
  • 開発環境で cvs tag か cvs rtag でタグを付ける (PHASE99_RELEASE など)
  • リポジトリをまるごと tar で固めて商用環境へ持っていく。修正したファイルだけを選んで持っていかないこと。手で選別すると必ず漏れが発生するため。
  • 商用環境のリポジトリを削除 (または mv でリネーム)
  • 商用環境にて tar を展開して、リポジトリを配置
  • 商用環境にて cvs diff を行い、商用環境のファイルを直接いじった人がいないことを確認 (念のため)。
  • 商用環境にてソース置き場・バイナリ置き場などを全てリネーム (例: mv src src.old)
  • 商用環境にてソースをチェックアウト
  • 商用環境にてソースを make
もしリリース後に商用環境でバグが発見された場合の手順は以下のとおり。
  • できれば開発環境で原因究明。
  • 原因がわかったら開発環境でソースを修正してコミット。
  • 開発環境から商用環境にリポジトリを持っていって再リリース
もし時間的・物理的制限により、商用環境にて原因究明せざるをえない場合は以下のようにする。
  • 商用環境で原因究明。必要ならソースを修正してもよい。
  • 正常に動いたら cvs diff の結果を開発環境に持っていく (cvs diff でパッチを作成してもよい)。
  • 開発環境で修正版をコミット。
  • 開発環境から商用環境にリポジトリを持っていって再リリース
とにかく商用環境でコミットしないこと。もし商用環境と開発環境でそれぞれのリポジトリにコミットするようなことがあると、どちらがマスタかわからなくなってしまう。リポジトリの流れを「開発環境→商用環境」の一方向に限定するのがポイントである。

開発サイクルとブランチ
長期間の開発では、数ヶ月ごとにフェーズ 1、フェーズ 2、フェーズ 3 …などと開発・テスト・リリースのサイクルを繰り返すのが一般的である。基本的にはフェーズ n とフェーズ n+1 は重ならないはずであるが、フェーズ n のリリース前にフェーズ n+1 の開発を開始しなければならない状況もあるだろう。また、フェーズ n+1 の開発中にフェーズ n のバグが発覚したので修正ソースをコミットしたいときもある。

いずれの場合でも、一般的にはブランチを導入すべきケースである。しかし当ページ管理人の私見では、CVS のブランチは非常にわかりづらい。テキストベースでは分岐状況を直観的に把握するのは難しく、現在修正中のファイルが trunk なのかブランチなのかも混乱しがちである。慣れている人が操作するのであれば全く問題ないが、プロジェクトメンバのスキルが低い場合はブランチを導入するのはためらわれる。

そこで提案するのが、フェーズごとにモジュールをコピーして管理する方法である。Phase1 の開発時は
$CVSROOT/Phase1/
にてソースを管理する。Phase1 の商用リリースが完了し、Phase2 の開発が始まったら、
% cd $CVSROOT
% cp -rp Phase1 Phase2
とモジュールをコピーし、
% cvs checkout Phase2
というふうにソースを取得して開発する。もし Phase1 の商用リリース後にバグが発見された場合は、Phase1 に対して修正を行うとともに、Phase2 に対しても同じ修正を行う。フェーズを重ねるごとに
$CVSROOT/Phase1/
$CVSROOT/Phase2/
$CVSROOT/Phase3/
$CVSROOT/Phase4/
とモジュールが増えていくので、4世代前の古いリポジトリは削除してよい、などと決めておけばよいだろう (Phase1 の履歴が削除されるわけではないことに注意。リポジトリをPhase1 の履歴は Phase2〜4 全てに含まれている)。

上記のモジュールをコピーする方法を取るにせよ、あるいはブランチを導入するにせよ、いずれの場合でも並行開発期間をできる限り短くしよう。Phase1 の商用リリース直後に Phase2 のモジュールをコピーまたはブランチを作成するのではなく、Phase2 の設計が完了し、ソースを作成し、コミットが必要になったときに初めて Phase2 のモジュールをコピーまたはブランチを作成する。
>> コマンド CVSチュートリアル基礎編 *   CVSチュートリアル応用編 *   CVSトピック編 *

date 現在の時刻 (日時) を表示・設定する

引数なしで実行すると、現在の時刻を表示する。
% date
Sun Oct 10 10:38:28 JST 1999
-u オプションを与えると、世界標準時で表示する。
% date -u
Sun Oct 10 01:38:58 GMT 1999
「+」のあとに文字列を指定すると、任意のフォーマットで表示できる。
% date "+%Y/%m/%d%n %H:%M:%S"
1997/2/25
06:04:41
フォーマットの書式は以下の通り。より詳しい書式は、strftime(3) を参照してほしい。
%y 年 (2桁表示)
%Y 年 (4桁表示)
%m 月 (2桁表示)
%d 日 (2桁表示)
%h 月 (英語表示 Jan,Feb...)
%H 時
%M 分
%S 秒
%n 改行
%t タブ
%% 「%」自体

n 時間後、n 日後、n ヵ月後などの時刻を知りたい場合は -v オプションを使えばよい。
% date -v+1y (1年後の時刻を表示)
% date -v+2m (2ヵ月後の時刻を表示)
% date -v+3w (3週間後の時刻を表示)
% date -v+4d (4日後の時刻を表示)
% date -v+5H (5時間後の時刻を表示)
% date -v+6M (6分後の時刻を表示)
% date -v+7S (7秒後の時刻を表示)
過去に戻る場合はプラスをマイナスに変える。
% date -v-1y (1年前の時刻を表示)
% date -v-2m (2ヵ月前の時刻を表示)
今から 1年後の 2週間前の時刻は、-v を複数回指定して
% date -v+1y -v-2w
とする。ただし、-v は BSD や GNU の date コマンドにしかなく、例えば Solaris の date では使えない。その場合はタイムゾーンを設定することで、ある程度までは対応できる (このような使い方はタイムゾーン本来の用途ではない)。

例えば日本時間は世界標準時間 GMT (≒UTC) より9時間早いので、
% date

% env TZ=JST-9 date
と等価である。よって、1日前 (24時間前) の日付を知りたければ -9+24=15 というタイムゾーンを設定すればよい。1日後 (24時間後) なら -9-24=-33 とすればよい。
% env TZ=JST+15 date (1日前の時刻を表示)
% env TZ=JST-33 date (1日後の時刻を表示)
タイムゾーンをプラスにすれば過去にさかのぼり、マイナスにすれば未来の時刻となることに注意。

date コマンドを使って現在時刻を設定することもできる。当然ながら時刻設定は root でないとできない。
# date 9803301445
⇒ 現在時刻を1998年3月31日14時45分に設定する。
# date 0632
⇒ 現在時刻を6時32分に設定する。日付は変更しない。
ネットワークを利用して正確な時刻に設定するには ntpdate を使うとよい。
>> コマンド ntpdate *

dc 逆ポーランド記法の計算機

計算式を逆ポーランドに変換すると、括弧の優先順位などを気にせず、先頭から順番に処理していくことがでる。逆ポーランドはコンピュータ向けの書き方で、人間が使う場合は、bc コマンドなどを使うとよい。
% dc
2 3 + (2+3の結果をスタックにpush)
p (スタックの先頭を表示)
5 (結果は5)
1 2 + 5 3 - * ( (1+2)*(5-3)の結果をスタックをpush)
p (スタックの先頭を表示)
6 (結果は6)
>> コマンド bc *   calc *   xcalc *   hexcalc *

decayscreen 画面が溶けていくデモ。スクリーンセーバか?

-root 画面全体を溶かす。
-delay usec 画面を溶かす処理の間にusecのウェイトをいれる。
(単位はマイクロセカンド)

dd ファイルのコピー・ディスクダンプ・バックアップ・リストア・ファイル作成

【この項目の説明はかなり怪しげなので注意すること】

dd は入力から出力へデータをコピーするコマンドである。cp はファイルからファイルにコピーするだけであるが、dd はファイルからデバイス、デバイスからファイル、デバイスからデバイスへのコピーも可能なため、ディスクのバックアップやダンプにも使用できる。

ディスクのコピー
# dd if=/dev/ad0 of=/dev/ad1
⇒ /dev/ad0 を /dev/ad1 にコピーする。ただし両方のディスクが同容量でなくてはならない。

フロッピーのコピーなども可能。
# dd if=/dev/rfd0 of=fdd.flp
⇒ FDD の内容をファイルにダンプ
# dd if=kern.flp of=/dev/rfd0
⇒ フロッピーのイメージファイルを FDD にコピー。OS インストールフロッピー作成時によく使う。

ディスクのバックアップとリストア
バックアップやリストアは、シングルユーザモードに落とすか、デバイスを umount してから行うこと。
# dd if=/dev/ad0 of=ad0backup.dump
⇒ HDD からファイルへのバックアップ
# dd if=ad0backup.dump of=/dev/ad0
⇒ リストアは、バックアップのときと if・of を逆にする
データ量が大きいときは gzip で圧縮することもできる。
# dd if=/dev/ad0 | gzip -c > ad0backup.dump.gz
⇒ 圧縮しつつバックアップ
# gzip -dc < ad0backup.dump.gz | dd of=/dev/ad0
⇒ 伸長しつつリストア
ネットワーク越しのバックアップ
# tar cf - . | rsh remotehost dd of=/dev/テープデバイス名 obs=20b

ファイルのバックアップとリストア
ディスクだけでなく、ファイル単位でもバックアップできる。とはいえ 1ファイルだけバックアップしていても、あまりうれしくない。
# dd if=.cshrc of=/dev/ad0
⇒ .cshrc を HDD にバックアップ
# dd if=/dev/ad0 of=.cshrc
⇒ .cshrc を HDD からリストア

ファイル作成
指定サイズのファイル作成も可能である。例えば /dev/zero を入力ファイルに指定することで、全データが NULL のファイルが生成できる。ファイルサイズは「count で指定したブロック数×ブロックサイズ」となる。デフォルトのブロックサイズは 512 だが、bs で変更可能。
% dd if=/dev/zero of=zero.dat count=1000
⇒ 512*1000 バイトの zero.dat が生成される
% dd if=/dev/zero of=zero.dat count=2048 bs=1
⇒ ブロックサイズを 1 に指定。2048 バイトの zero.dat が生成される

Solaris でファイル生成をするなら、mkfile コマンドを使ってもよい。
>> コマンド mkfile *

主要オプション一覧
if=[ファイル] 入力ファイル (デバイス)。指定しないと標準入力。
of=[ファイル] 出力ファイル (デバイス)。指定しないと標準出力。
bs=[サイズ] 入出力のブロックサイズを指定。ibs と obs の両方に同じ値をセットする場合に使用する。
ibs=[サイズ] 入力のブロックサイズを指定
obs=[サイズ] 出力のブロックサイズを指定
count=[ブロック数] コピーするブロック数を指定
conv=変換オプション 変換オプションを指定 (後述)。conv=hoge,fuga などと複数指定も可能。
seek=[ブロック数] 出力の開始位置を指定されたブロックに移動してからコピーする
oseek=[ブロック数] FreeBSD では seek と同じ。Solaris では違うっぽい…?
skip=[ブロック数] 入力の開始位置を指定されたブロックに移動してからコピーする
iseek=[ブロック数] FreeBSD では skip と同じ。Solaris では skip より速いと書いてある…?

サイズには数字のほか、k・m・g などの単位を指定できる (ブロック数にも使えるけど混乱するかも)。
bs=1 1バイト
bs=1b 512バイト (b はバイトではなくブロック)
bs=1k 1KB
bs=1m 1MB
bs=1g 1GB

conv に指定できる変換オプションうち、主要なものを以下にあげる。
◯noerror
HDD 読み取りエラーなど、入力でエラーが発生した場合でも終了せずに処理を続行する。noerror を指定しないと、dd はエラー発生時にすぐ終了してしまう。noerror を指定する場合は、必ず sync も指定すること (conv=noerror,sync)。これにより、エラーの部分は NULL で埋められて出力にコピーされる。sync を付けないとエラー部分は出力されない。また、noerror 指定時は count を明示的に指定すること (終端に達しても止まらなくなるらしい)。

◯sync
入力ブロックを、入力バッファサイズになるように NULL でパディングする。

◯notrunc
既に out.dat が存在し、ファイルサイズが 2048 バイトだったとする。この状態で
% dd if=/dev/zero of=out.dat count=1 bs=512
とすると、out.dat のファイルサイズは 512 バイトに切り詰められてしまう。一方、
% dd if=/dev/zero of=out.dat count=1 bs=512 conv=notrunc
と conv=notrunc を付けると、out.dat の先頭 512 バイトが NULL で埋められるが、513〜2048 バイト目までは最初のファイルの状態のまま残される。

コピー対象のサイズは「ブロックサイズ×ブロック数」で決まるため、以下のそれぞれのコマンドで生成されるファイル内容は全く同じであるが、ブロックサイズが小さすぎると時間がかかってしまうことに注意。
% dd if=/dev/zero of=zero.dat bs=1 count=51200000
⇒ 実行時間 3秒
% dd if=/dev/zero of=zero.dat bs=512 count=100000
⇒ 実行時間 2.5秒
% dd if=/dev/zero of=zero.dat bs=51200000 count=1
⇒ 実行時間 13分

なお、この例では入力がファイルであるためブロックサイズはどんな値でも (速度以外は) 問題ないが、入力がデバイスの場合は適切な値に設定する必要がある。ブロックデバイスの場合、ブロックサイズはセクタサイズの整数倍でなくてはならない (という表現であっているのだろうか)。
% dd if=/dev/ad0 of=ad0-backup.dump bs=1
dd: /dev/ad0: Invalid argument
⇒ 小さすぎてもエラー
% dd if=/dev/ad0 of=ad0-backup.dump bs=513
dd: /dev/ad0: Invalid argument
⇒ 大き過ぎてもエラー
% dd if=/dev/ad0 of=ad0-backup.dump bs=512
⇒ 1セクタ=512 バイトなので、OK
% dd if=/dev/ad0 of=ad0-backup.dump bs=1024
⇒ 整数倍なので OK
% dd if=/dev/ad0 of=ad0-backup.dump bs=8192
⇒ これも OK。一気に読み込むので、bs=512, bs=1024 より速いかもしれない
上記の bs=1 の例でエラーになるのは、そもそも /dev/ad0 に対する 1バイト分の read(2) がエラーとなるからである (Invalid Argument)。

また、「conv=noerror,sync」を指定した場合は、ブロックサイズを最小のセクタ単位で指定した方がよいとか。エラーが発生したブロックのみ NULL で埋められるらしい。
% dd if=/dev/ad0 of=zero.dat bs=512 count=.... conv=noerror,sync
⇒ 1セクタのみエラーになる場合は 512 バイトだけ NULL 埋めされる (のか?)
% dd if=/dev/ad0 of=zero.dat bs=1024 count=.... conv=noerror,sync
⇒ 動きはするが、お勧めしない。1セクタのみエラーになる場合でも、1024 バイトが NULL 埋めされてしまう (ということか?)

SIGINFO による状態通知
FreeBSD の dd は SIGINFO シグナルを受けると、現在の状態を表示する (処理はそのまま続行する)。
% dd if=/dev/zero of=zero.dat count=10000000
(処理中なので何も表示されないが、ここで Ctrl-t を押して SIGINFO を飛ばす)
load: 0.05 cmd: dd 5500 [running] 0.06u 0.93s 0% 564k
47717+0 records in
47717+0 records out
24431104 bytes transferred in 1.235103 secs (19780622 bytes/sec)
⇒ 入力・出力レコード数・バイト数などの情報が表示され、さらに処理は続く
(再度 Ctrl-t)
load: 0.12 cmd: dd 5500 [running] 0.12u 3.00s 0% 588k
145009+0 records in
145008+0 records out
74244096 bytes transferred in 3.606494 secs (20586225 bytes/sec)
⇒ 実行中であれば何度でも Ctrl-t で最新の状態を表示できる

余談
dd コマンドの機能は「convert and copy a file」なので本当は cc コマンドにしたかったが、既に C コンパイラが cc という名前を使っていたので、仕方なく cc の次の dd にしたらしい。
>> コマンド cp *   mkfile *
>> 用語集 穴あきファイル *
>> 読み方 dd *

df ディスクの使用状況を表示

ファイルシステムごとに、デバイス名、全容量、使用容量、残り容量、使用割合、マウント先を表示する。
% df -k
Filesystem  1K-blocks     Used    Avail Capacity  Mounted on
/dev/sd0s1a    118959    71251    38192    65%    /
/dev/sd0s1f   3540086  2488705   768175    76%    /usr
/dev/sd0s1e    197951    19640   162475    11%    /var
procfs              4        4        0   100%    /proc
/dev/cd0c      662942   662942        0   100%    /cdrom
オプション
-k 512バイト単位ではなく、1キロバイト単位で表示
-i i-node の消費量も表示
i-node はファイルを作成するたびに必ず一つ必要となる。i-node を全て使いつくすと、ディスク容量に空きがあっても新たなファイルを作成できなくなる。iused・ifree・%iused が i-node に関わる情報で、それぞれ「使用中の i-node」「未使用の i-node」「i-node の使用率」である。
Filesystem  1K-blocks     Used    Avail Capacity iused   ifree %iused  Mounted on
/dev/ad0s1a  37352396 16260170 18104036    47%  363569 4464589    8%   /
devfs               1        1        0   100%       0       0  100%   /dev
procfs              4        4        0   100%       1       0  100%   /proc
linprocfs           4        4        0   100%       1       0  100%   /usr/compat/linux/proc
-H 人間が読みやすい単位で表示
% df -H
Filesystem    Size   Used  Avail Capacity  Mounted on
/dev/ad0s1a    38G    17G    19G    47%    /
devfs         1.0K   1.0K     0B   100%    /dev
procfs        4.1K   4.1K     0B   100%    /proc
linprocfs     4.1K   4.1K     0B   100%    /usr/compat/linux/proc

普通 df コマンドをオプションなしで実行すると、容量が 512 バイト単位で表示されてしまい わかりにくいので、上の例のように -k オプションを使うとよい。また、-k オプションの代わりに環境変数 BLOCKSIZE を設定しておく手もある。
>> 環境変数 BLOCKSIZE *

df で表示される使用割合 (capacity) は 100% となっていても本当にディスクが一杯になっているわけではなく、ある程度余裕を持たせてある。この余分なスペースは速度向上のために使われているので、一般ユーザはこのスペースを利用することができない。ただし root だけは領域全体を使用することができる。もし限度一杯までファイルを作成すると、df の表示が 100% を越えて「110%」などと表示される。

FreeBSD 2.2.7-RELEASE〜5.2.1-RELEASE では、この余分なスペースが全体の 8% 確保される。このパーセンテージは、フォーマット時に newfs コマンドで指定することができるが、tunefs コマンドで動的に変更することも可能である。

Solaris や HP-UX 標準の df (つまり SystemV の df) では、以下のように使用率が表示されないため、わかりづらい。
% df
/                  (/dev/dsk/c0t0d0s0 ):  632572 ブロック   309231 files
/proc              (/proc             ):       0 ブロック     7851 files
/dev/fd            (fd                ):       0 ブロック        0 files
/opt               (/dev/dsk/c0t0d0s3 ): 3287522 ブロック   302842 files
/usr/local         (/dev/dsk/c0t0d0s5 ): 2832984 ブロック   325437 files
/home              (/dev/dsk/c1t1d0s0 ):39442983 ブロック  1904820 files
Solaris であれば
% df -k
HP-UX であれば
% bdf
とすることで、使用率を表示することができる。
>> 設定ファイル /etc/fstab *
>> 用語集 ファイルシステム *   ファイル制限まとめ *
>> 読み方 df *

diff ファイルの違いを表示。パッチを作成。(差分・差異・比較)

差分表示
2つのファイルの違いを表示する。
% diff file1 file2
とすると、file1 と file2 の相違点を表示する。システムの設定ファイルをいじる場合は、最初に
% cp rc.conf rc.conf.org
などとオリジナルを保存し、適時
% diff rc.conf rc.conf.org
として差分を取ることで、修正点が一目でわかる。

ファイル名として - を指定すると標準入力と比較する。例えば
% command | diff - file
は command の出力と file の内容を比較する。また、foo/bar.dat と hoge/bar.dat を比較したい場合のように、ファイル名が同一の場合は、
% diff foo/bar.dat hoge
のように、一方のファイル名は省略できる。

引数の両方にディレクトリ名を指定した場合は、2つのディレクトリ以下に存在するファイルの差分を表示する。
% diff dir1/ dir2/
ただし、片方のディレクトリにしか存在しないファイル、例えば dir1 の下に存在するが dir2 の下には存在しないファイルの情報は表示しない。両方のディレクトリに同じ名前のファイルがある場合のみ、差分を表示するだけである。また、-r オプションを指定することで、再帰的にサブディレクトリをたどっていく。例えば、
dir1/file1
dir1/subdir1/
dir1/subdir1/subfile1
dir1/subdir1/subfile2
dir2/file1
dir2/file2
dir2/subdir1/
dir2/subdir1/subfile1
dir2/subdir2/subfile1
というファイルが存在したとき、
% diff dir1/ dir2/
では、dir1/file1 と dir2/file1 の差分しか表示しない。
% diff -r dir1/ dir2/
だと、dir1/file1 と dir2/file1、dir1/subdir1/subfile1 と dir2/subdir1/subfile1 の差分しか表示しない。

パッチ作成
パッチを作成するときにも diff コマンドが使える。まず最初にパッチの形式について説明せねばなるまい。パッチには主に context 形式、unified 形式の2種類がある (他にもノーマル形式と ed 形式があるが省略)。file.txt.org と file.txt という2つのファイルを例にあげる。
% cat file.txt.org
abc
def
hij
% cat file.txt
abc
XXX
hij
file.txt.org と file.txt の違いは2行目の「def」と「XXX」だけである。オプションを付けずに diff コマンドを実行すると、
% diff file.txt.org file.txt
2c2
< def
---
> XXX
となる。これがノーマル形式である。出力を context 形式にするには -c オプションを付ける。
% diff -c file.txt.org file.txt (context 形式で出力)
*** file.txt.org Sun Sep 12 07:43:26 1999
--- file.txt Sun Sep 12 07:43:34 1999
***************
*** 1,3 ****
abc
! def
hij
--- 1,3 ----
abc
! XXX
hij
という形式になる。一方、-u オプションを付けると unified 形式になり、
% diff -u file.txt.org file.txt (unified 形式で出力)
--- file.txt.org Sun Sep 12 07:43:26 1999
+++ file.txt Sun Sep 12 07:43:34 1999
@@ -1,3 +1,3 @@
abc
-def
+XXX
hij
と、その名の通り unified (統一された) な出力が得られる。context diff や unified diff は、ノーマル形式と違い、「どのファイルの差分であるか」という情報が含まれているが、ノーマル形式 (オプションを付けないで実行) や ed 形式 (-eオプション) では、ファイルの情報が含まれていない。

つまり、ノーマル形式や ed 形式のパッチを patch コマンドで当てようとすると、パッチを当てるべきファイル名をユーザ自身が入力しなければならない。しかし、context 形式や unified 形式なら、パッチファイル自体にパッチの対象となるファイルの情報が含まれているので、わざわざユーザがファイル名を指定する必要はない。よって、パッチを作成する際は、context か unified 形式を使うべきである。なお、context と unified のどちらを使うかは好みの問題。以降の例では unified 形式を使うが、特に理由はない。

では、本題であるパッチの作り方を説明する。file.txt.org と file.txt のパッチを patch.txt に保存する。
% diff -u file.txt.org file.txt > patch.txt
ここで大事なのは、引数で指定する file.txt.org と file.txt の順番である。パッチを作るということは、誰かにパッチを当てて欲しいわけである。その「誰か」の手元には、当然どちらかのファイルしか存在しない (両方あるならパッチを当てる必要はない)。引数の最初に指定するのは、
「元のファイルと同じ内容のファイル名」(from-file)
2番目に指定するのは
「改変後のファイル名」(to-file)
である。

パッチを当てる人の手元には、file.txt という名前の
abc
def
hij
というファイルがあるはずである。一方、こちらの手元には、このファイルと同じ内容の file.txt.org と、内容を変更した新しい file.txt がある。よって、
% diff -u file.txt.org file.txt
という順番にしなければいけない。この順番を逆にするとリバースパッチになってしまう。
リバースパッチ・パッチの当て方は、patch コマンドの説明を参照してほしい。

オプション
-c context diff 形式の出力をする。
-u unified diff 形式の出力をする。
-e ed diff 形式の出力をする。普通は使わない。
-r ディレクトリを比較したとき、その下のサブディレクトリを再帰的にたどっていく。
-a テキストファイルとして比較する。
-b 空白・タブの数の違いを無視する。
-i 大文字・小文字の違いを無視する。
-B 空行のある・なしの違いを無視する。
-y 2つのファイルを、横に並べて表示する。
十分な端末の横幅がないと見にくくなってしまう。-W オプションで横幅を指定できる。
-W -y オプションを付けたときの、横幅を指定。
% diff -y -W60 file1 file2
⇒ 差分を横に並べて表示。横幅は60文字。
-q ファイルが同じかどうかだけを表示する。

バイナリファイルのパッチ生成には、xdelta や bsdiff を使う。
>> コマンド patch *   cmp *   comm *   diff3 *   zdiff *   bsdiff *   xdelta *

diff3 3つのファイルの違いを表示 (差分・差異・比較)

>> コマンド diff *   zdiff *

dig 名前解決を行う

dirname パス名+ファイル名からファイル名を削除する

>> コマンド basename *   realpath *

display 画像を表示・編集する(ImageMagick)

>> コマンド convert *   identify *   ImageMagick *   xv *

dmesg システムのメッセージを表示

OS のブート時のメッセージを、ブート後に参照したい場合に使う。また、ディスクが一杯でファイルを書き込めなかった、などのエラーメッセージも表示される。しかし rc.local などで表示されるメッセージは表示されない。
>> 読み方 dmesg *

du 指定ディレクトリ以下のディスク使用量を再帰的に表示する

-L シンボリックリンクも計算する
-a 各ファイルごとに使用量を表示する
-d 深さ 指定したディレクトリの深さだけしか表示しない。
-k 単位をKBで表示する
du はデフォルトでは、ブロック単位で値を表示する。一般的なUNIXは1ブロック=512バイトとなっているので、普通に du を実行すると、値は512KB単位になってしまう。1Kバイト単位で表示したい場合は、-k オプションを付ける。また、環境変数 BLOCKSIZE に単位を指定してもよい。
% du … 512バイト単位
% du -k … 1キロバイト単位
% setenv BLOCKSIZE 1024
% du … 1キロバイト単位
% setenv BLOCKSIZE 1048576
% du … 1メガバイト単位
% setenv BLOCKSIZE 1073741824
% du … 1ギガバイト単位
>> 環境変数 BLOCKSIZE *
-s 指定ディレクトリのサブディレクトリの使用量を表示しない。
du / だと /usr、/bin、/etc、さらに /usr/bin や /usr/local/bin などの容量も表示するが、-s を指定すると
% du -s /
/ 6563241
と、全ての容量を合計した値が表示される。
% du -s /*
とすると、サブディレクトリを表示せずに / 以下の各ディレクトリのサイズを表示する。
-c 全てのファイル・ディレクトリの容量の合計を表示 (FreeBSD 2.2.7-RELEASE 以降)
>> コマンド xdu *
>> 読み方 du *

dvi2ps DVI ファイルを PostScript 形式に変換する

jlatex コマンドで DVI ファイルを作ったら、
% dvi2ps foo.dvi | lp -d printer_name
とすることで印刷できる。
>> コマンド xdvi *   gs *   dvi2tty *   a2ps *

dvi2tty DVI ファイルをコンソールでプレビューする

普通は DVI ファイルは xdvi でプレビューするが、xdvi を実行するには X が必要である。dvi2ttyは、DVI ファイルをテキスト形式に変換して出力するので、コンソール上からでもプレビューできる。ただしその分、文字の大きさや数式などの表示能力は低い。
>> コマンド xdvi *   dvi2ps *

echo 文字列を表示

echo は引数で与えた文字列を標準出力に出力するだけのコマンドである。シェルの内部コマンドの echo と、/bin/echo が存在することに注意。
% echo abc
abc
⇒ 引数で指定した文字列を表示する
% echo abc def abc def
⇒ 複数の引数を与えると、すべてを表示する
% echo "*hoge fuga~ [??]" *hoge fuga ??
⇒ メタキャラクタや連続した空白を含む場合はダブルクォートで囲む
% echo $path /sbin /bin /usr/sbin /usr/bin /usr/games /usr/local/sbin ...
⇒ シェル変数を表示
% echo $PATH /sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:...
⇒ 環境変数を表示

echo コマンドにおける改行抑止には 2種類の方法があり、統一したやり方は存在しない。
% echo -n abc; echo def
abcdef
⇒ -n オプションを指定すると、最後の改行を抑止する echo もある
% echo 'abc\c'; echo def
abcdef
⇒ 一方、末尾に \c を付けると、最後の改行を抑止する echo もある
例えば FreeBSD・Linux の /bin/echo は -n 派、Solaris など SystemV 系の /bin/echo は \c 派、FreeBSD の sh (ash) は -n 派、bash は -n 派、tcsh はデフォルトでは -n 派だがシェル変数 echo_style で変更可能、といったカオス状態である。改行について悩みたくない場合は、echo コマンドではなく printf コマンドを使うこと。
>> コマンド printf *

csh・tcsh の内部コマンドである echo コマンドで改行を抑止する方法については、シェル変数 echo_style を参照。
>> Cシェル変数 echo_style *

echo は xargs と組み合わせても便利である。
>> コマンド xargs *
>> 用語集 ファイルグロブ *

egrep 拡張正規表現を使える grep

egrep は grep -E とほぼ同じで、指定した検索パターンは拡張正規表現として扱われる。ただし、grep -E では {} が繰り返し回数を表すが、egrep で {} を使うと、ただの `{}' という文字列として扱われる。
>> コマンド grep *   fgrep *   zgrep *   agrep *
>> 読み方 egrep *

elvis 日本語を表示できる vi

>> コマンド vi *

emacs 高性能エディタ

とっても有名なエディタ。詳しい説明は mule の項を参照。
>> コマンド mule *   xemacs *

enlightenment グラフィカルなウィンドウマネージャ

あきれるほど高機能。あきれるほどのカスタマイズが可能。その分、あきれるほど重い。ごてごてしたウィンドウマネージャがお好みなら、試してみる価値は十分にある。
>> コマンド twm *   fvwm *   fvwm2 *   fvwm95-2 *   afterstep *

env 環境変数をセットしてコマンドを実行

特定のコマンドだけに環境変数を認識させたいときに使う。
% env LANG=ja_JP.eucJP netscape &
% alias jman LANG=ja_JP.eucJP jman
% alias jman env LANG=ja man
環境変数を
% env A=1 B=2 C=3 command
などと羅列することで、複数の環境変数を同時に指定することもできる。

引数に `-' を付けると、全ての環境変数がクリアされる。
% env - printenv
printenv は環境変数を全て表示するコマンドだが、env の引数に `-' を付けているので、全ての環境変数がクリアされてから printenv を実行するため、printenv は何も表示しないはずである。

`-' の後に環境変数を指定することで、特定の環境変数以外をクリアしてコマンドを実行することもできる。
% env - TEST=sample printenv
TEST=sample

>> コマンド printenv *   setenv *
>> 用語集 シェバング *

Eterm 背景に画像を貼れるターミナルソフト

背景に画像を貼ることができる。Enlightenment と密接に関係しているが、他のウィンドウマネージャからも利用可能。
% Eterm --background-pixmap file
で、file を背景に貼ることができる。file には、pixmap・GIF・JPEG など、ほとんどの画像形式を指定することができる。その他のほとんどのオプションは、xterm・kterm などと共通 (kterm の項を参照)。

kterm、xterm のように古くからあるコマンドではないので、結構不安定。ウィンドウサイズを変更すると簡単に落ちてくれる。日本語の表示、kinput2 からの入力もできるらしいが、こちらの環境では成功していない。
>> コマンド enlightenment *   kterm *   xterm *

ethereal パケット監視ツール

ネットワークを流れるパケットを解析するツール。tcpdump のようなキャラクタベースのプログラムとは違い、GUI で操作・表示が可能。プロトコルの学習用には特に効果的。

使用例は http://X68000.q-e-d.net/~68user/net/resolver-1.html を参照。
>> コマンド tcpdump *

euctosj 文字コードを変換する (パイプ)

Solaris 標準の EUC-JP・Shift_JIS・ISO-2022-JP の文字コード変換コマンド。ここでは代表的に euctosj をあげたが、全部で 6つのコマンドが用意されている。
  • euctosj … EUC-JP から Shift_JIS に変換
  • euctojis … EUC-JP から ISO-2022-JP (JIS) に変換
  • sjtoeuc … Shift_JIS から EUC-JP に変換
  • sjtojis … Shift_JIS から ISO-2022-JP (JIS) に変換
  • jistoeuc … ISO-2022-JP (JIS) から EUC-JP に変換
  • jistosj … ISO-2022-JP (JIS) から Shift_JIS に変換
>> コマンド nkf *   qkc *   iconv *

exec 現在実行中のシェルに代わり、指定したコマンドを実行する

シェルから
% ls
とコマンドを実行すると、シェルは以下のことを行う。
  • システムコール fork(2) を呼び、子プロセスを生成する。
  • 子プロセスは ls を exec(2) する。
  • 親プロセスであるシェルは、ls の実行が完了するのを待つ (wait する)。

一方、
% exec ls
と exec を使うと、シェルは fork(2) せず、いきなり ls コマンドを exec(2) する (シェルの内部コマンド exec(1) を実行すると、内部でシステムコール exec(2) が呼ばれるということ)。シェルのプロセス情報は ls のプロセスの情報で上書きされる。なお、子プロセスは生成されないので、シェルと ls のプロセス ID は同じになる。

実際にやってみるとわかるが、kterm などの端末エミュレータ上でシェルを動かしているときに
% exec ls
とすると一瞬 ls の結果が実行されるが、kterm は終了してしまう (kterm は通常シェルが終わるのを待っているが、シェルのプロセスは ls のプロセスに上書きされるので、ls が終了すると kterm も終了してしまう)。

exec のつかいどころは以下のとおり。

例 1. ~/.xinitrc や ~/.xsession
~/.xinitrc や ~/.xsession では、通常 kterm などの端末エミュレータを数個呼び、twm や fvwm などのウィンドウマネージャを起動する。ここで
#!/bin/sh
kterm -g 102x60+10+10 &
kterm -g 90x52-10-10 &
twm
ではなく、
#!/bin/sh
kterm -g 102x60+10+10 &
kterm -g 90x52-10-10 &
exec twm # ここで exec を使う
と書くとよい。前者は twm を実行している間 (≒ユーザがログインしている間)、sh がずっと twm の終了を待っている。しかし後者は sh のプロセスは twm のプロセスで上書きされてしまうので、前者よりプロセス数が一つ少なくてすむ。

例 2. wrapper スクリプト
例えば FreeBSD 4.7-RELEASE の /usr/bin/pagesize。中身は以下のような sh スクリプトで、sysctl を実行するだけの wrapper スクリプトである。
#!/bin/sh -
PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH
exec sysctl -n hw.pagesize
これも sysctl を実行する間、/bin/sh を待たせなくてよいという効果がある。

同様に、FreeBSD 4.7-RELEASE で調べてみると、
  • /usr/bin/clear は tput を exec する
  • /usr/bin/sockstat は netstat を exec する
  • /usr/bin/perldoc は perl を exec する
  • gs 付属のプログラム (pf2afm、ps2pdf など) は gs を exec する
などなど、多くの wrapper スクリプトが exec でコマンドを呼んでいる。

まとめ
exec による効果は以下の通り。
  • fork(2) で子プロセスを生成しなくてすむ。fork(2) はかなり重いシステムコールである。fork(2) が重いので、vfork(2) が作られたくらい重い。ただ、現代の UNIX では copy-on-write の効果により、以前ほど fork(2) が重いわけではない。
  • 親プロセスが子プロセスの終了を待つ必要がない。1 プロセス分浮くわけである。

exec を 1回使うことによる速度向上・メモリ量削減効果はたいしたことはない。ただし数百回・数千回分続くようなら、塵も積もれば…となる。例えば大学のような「1つの大型サーバと数十台の X 端末」という状況で、上記の例 1 を考えると、
twm
の部分を
exec twm
とするだけで、一気に数十プロセスが浮くわけである。

export 環境変数を設定する。sh・bash の内部コマンド。

sh・bash で環境変数を設定するには、まずシェル変数をセットし、その後に export を実行する。
FOO="BAR"
export FOO
bash や FreeBSD の sh (ash) では、いきなり export を実行することで環境変数の設定が可能である。
export FOO="BAR"
ただし、Solaris や HP-UX などの sh では上記のようなやり方はエラーとなる。移植性を重視する場合は一度シェル変数に値をセットしてから export を実行することをお勧めする。

export した環境変数を削除するには unset コマンドを使う。
$ FOO="BAR"
$ export FOO
$ printenv FOO
BAR
⇒ FOO=BAR であることがわかる
$ unset FOO
$ printenv FOO
⇒ 何も表示されない (環境変数が削除されたということ)

csh・tcsh で環境変数を設定するには setnev コマンドを使用する。
>> コマンド env *   printenv *   setenv *   set *

exit 現在のシェルを終了する。シェルの内部コマンド。

ログアウトした後も、プログラムを実行させ続けたければ nohup を使うとよい。

もし Ctrl-Z や stop コマンドなどでサスペンド (中断) したジョブがあるのに exit しようとした場合、
There are suspended jobs.

You have stopped jobs.
などと警告されてシェルは終了しない。jobs コマンドで実行中のジョブを確認し、対処しよう。

警告が出ても、もう一度 exit とすればサスペンドしたジョブを残してシェルは終了する。その場合はプロセスに SIGHUP が送られ、(大抵の場合は) プロセスは終了する。しかしなるべくジョブを自分で始末してから exit する方がよいだろう。
>> Cシェル変数 ignoreeof *   savehist *
>> コマンド nohup *   jobs *

expand ファイル中のタブをスペースに変換する (パイプ)

fold や TeX の文章中などは、タブを認識してくれないので、事前にタブをスペースに変換しておく必要がある。expand コマンドの代わりに、emacs や mule の M-x untabify を使ってもいい。
>> コマンド unexpand *

f77 Fortranコンパイラ

factor 数字が素数かどうか調べる

FreeBSD では /usr/games/ の下にインストールされるので注意。
>> コマンド primes *

fd ファイル・ディレクトリ管理ツール

fdformat フロッピーディスクをフォーマットする


fetch FTP・HTTP ダウンローダ

(再帰的にダウンロードするのでなく) 一つのファイルだけをダウンロードしたいときに重宝する。もしかしたら FreeBSD にしか存在しないコマンドかもしれない。
% fetch ftp://www.foo.bar/pub/hoge.tar.gz
とすることで、指定のファイルをダウンロードし、カレントディレクトリの hoge.tar.gz に内容を保存する。HTTP も
% fetch http://www.foo.bar/hoge/fuga.html
と可能であるが、
% fetch http://www.foo.bar/hoge/
のように、最後がファイル名で終っていない場合はダウンロードできない(これはバグであろう。将来修正されると思う)。

-p FTP のパッシブモードを使う。ファイアーウォール内部からダウンロードしたい場合に有効。
-r リトライ。以前に中断されたファイルの続きをダウンロードする。
一度ダウンロードしていたが、途中で接続が切れてしまい、ファイルの前半だけが手元にある場合、全体をダウンロードし直すのではなく残りの部分だけをダウンロードする。リトライできるのは FTP と HTTP/1.1 のみで、なおかつ相手側サーバがリトライに対応している必要がある。
-T タイムアウトまでの秒数を指定。
% fetch -T 30 http://www.foo.bar/hoge/fuga.html
⇒ 30 秒たってもダウンロードが終了しなければあきらめる。
>> コマンド ftp *   ncftp *   wget *
>> 環境変数 HTTP_PROXY *

fg 指定したジョブをフォアグラウンドで実行する

指定したジョブをフォアグラウンドで実行する。ジョブ番号を指定しないとカレントジョブが操作対象になる。

例えば mule を実行中に一時的に他の事をしたいとき、いちいち終了するのは面倒なので(muleの起動が遅いから)、Ctrl-Z で中断して別の事をやり、その後 fg で mule の処理を行う、というふうにすると便利。
>> コマンド bg *   jobs *   nohup *

fgrep 正規表現が無効となる grep。

fgrep は grep -F と全く同じである。指定した検索パターンは正規表現ではなく、普通の文字列として扱われる。

なお、fgrep は Fixed GREP の略である (Fast GREP ではない)。固定文字列の検索用、ということ。
>> コマンド grep *   egrep *   zgrep *   agrep *

file 指定されたファイルを解析して、ファイルの種類を表示する。

ファイルの種類がわからないときに使う。認識できるファイルの一例をあげると、
スクリプト
awk sed B-shell C-shell perl
ソース
アセンブラ C LISP Pl/1
実行ファイル
DOS FreeBSD/i386 NetBSD/i386 PDP-11
ファイルシステム
ソケット ディレクトリ シンボリックリンク ブロックデバイス
その他
アスキーテキスト 英文 ポストスクリプト TeXDVI 音声 画像 圧縮ファイル news mail make nroff troff アーカイブ SGML METAFONT PGMファイル TIFF emacsバイトコンパイル ハッシュテーブル
ファイルの一部を解析するため、間違えることも多く、xpm は C のソース、HTML は英文や C のソースと認識してしまう。

また、コアファイルに対して file コマンドを使うと、元のプログラム名を知ることができる。
% file core (/bin/catをコアダンプしたもの)
core: i386 a.out core file from "cat"
GIF や PNG ファイルに対しては
% file sample.gif
sample.gif: GIF image data, version 89a, 302 x 231,
と、高さと幅が表示される。その他の画像フォーマットに関する情報は identify で。
>> コマンド identify *

オプション
-z 指定ファイルが圧縮ファイルの場合、伸長して解析する。
-L シンボリックリンクの先のファイルを解析する
>> コマンド strings *

file2c 標準入力から読み込んだ文字列を ASCII コードに変換する。

標準入力から読み込んだ文字列を ASCII コードに変換する。
% echo abc | file2c
97,98,99,10
以下のように、プログラム用のデータファイル生成にも役に立つ。
% echo abc | file2c 'char buf[]={' '};'
char buf[]={
97,98,99,10
};

filepp 独自拡張プリプロセッサ

filepp は文字列を前処理する cpp と似たようなプリプロセッサである。以下のように使用する。
% filepp 入力ファイル > 出力ファイル

まず、filepp を cpp の代替として C 言語のソースを処理するために使用するのは避けた方がよい。理由は、インクルードファイルが存在しなかった場合の処理や、文字列リテラル ("hoge" のような文字列定数) を書き換えてしまうという仕様の違いがあるからである。

となると使いどころが難しいのだが、例えば
複数ホストの /etc/hosts などの設定ファイルを管理する際、元ネタとなるファイルをひとつだけ作っておき、filepp で各ホストの hosts を生成する
など、「静的データに対してちょっとした制御を行いたい」というときに使うとよいのではないかと思う。また、Java のようにプリプロセッサが存在しない環境で、プリプロセッサが必要になったときに filepp を使うのもよいかもしれない。

プリプロセッサの基本的な構文 (#include・#define・#ifdef など) は cpp の項を参照。同様に、cpp で使用できるオプションは filepp でも使用可能なことが多い。
>> コマンド cpp *

filepp では一般的な cpp を拡張し、独自の機能を持っている。デフォルトのままで使用できる拡張機能もあるが、多くの機能はモジュールを組み込まないと使用できない。モジュールを有効にするには -m オプションを使う。例えば for.pm モジュールを使う場合は
% filepp -m for.pm 入力ファイル > 出力ファイル
とする。以下、filepp 独自の拡張機能と、注意点を説明する。

文字列比較の拡張
通常のプリプロセッサでは文字列の比較はできない。
#if HOGE = 1
⇒ 数値の比較は OK だが…
#if HOGE = "hoge"
⇒ 文字列の比較はエラーとなる

一方、filepp では eq を使うことで文字列を比較が可能で、さらに「=~」でパターンマッチを使うことができる。
#if HOGE eq "string"
⇒ 文字列の比較には eq を使う
#if HOGE =~ /regexp/
⇒ パターンマッチは「=~」で

ループ (for.pm モジュール)
#for COUNTER 1 < 4 +1
printf("%d\n", COUNTER);
⇒ COUNTER は 1〜3 まで増分 +1 でループする
#endfor

ループ (foreach.pm モジュール)
#foreach FILE "file1.dat", "file2.dat", "file99.dat"
printf("%s\n", FILE);
#endfor
⇒ カンマ区切り記述した各要素を、ループ内で使用できる。

#foreachdelim / /
#foreach FILE "file1.dat" "file2.dat" "file99.dat"
printf("%s\n", FILE);
#endfor
⇒ foreachdelim を使うことで、foreach の区切り文字を変更できる。

#foreachdelim /\s+/
⇒ 区切り文字は正規表現で指定することも可能。

インクルードパス
cpp は /usr/include を標準のインクルードファイルパスとして特別扱いしている。一方、filepp はインクルードファイルパスは全て自分で -I オプションで指定する必要がある (/usr/include は特別扱いされない)。また、インクルードファイルが見つからなかった場合でもエラーとはならず、その行を削除して処理は続行される。

定義済マクロ
cpp と同様に、__FILE__・__LINE__ などが定義済マクロとして用意されているが、
printf("%s\n", __FILE__);
と書くと
printf("%s\n", foo.c);
というふうに文字列がダブルクォートで囲まれない形で置換されてしまう。もし一般的な cpp のような出力が欲しければ、cmacros.pm モジュールを使うこと。

コメント削除 (c-comment.pm モジュール)
C 言語・C++ 形式のコメント、「/* 〜 */」「//〜」を削除する。通常はコメントは出力ファイルに残るが、
% filepp -m c-comment.pm 入力ファイル > 出力ファイル
とすることで、コメントが削除されたものが出力ファイルに出力される。

複数行の define (bigdef.pm モジュール)
普通のプリプロセッサで複数行に渡る置換を行う場合、
#define foo(x,y,z) printf(\ 
   "x is %d\n"\ 
   "y is %s\n"\ 
   "z is %s\n",\ 
   x, y, z);
などと行末にエスケープを付ける必要があり、面倒で可読性が低くなる。しかし bigdef.pm モジュールを組み込むことで、
#bigdef foo(x,y,z)
   printf("x is %d\n"
          "y is %s\n"
          "z is %s\n",
          x, y, z);
#endbigdef
と #bigdef〜#endbigdef を使って読みやすい形で記述できる。

文字列リテラル内の文字列置換抑止 (literal.pm モジュール)
デフォルトでは filepp は文字列リテラルも置換対象とする (というより、filepp は「ここからここまでが文字列リテラル」などという解析は行っていない)。つまり、
#define hoge FUGA
printf("This is hoge.\n");
の出力結果は、
printf("This is FUGA.\n");
となる。しかし literal.pm モジュールを使用すると文字列リテラルかどうかを判断し、文字列リテラル内の文字列置換が抑止されるようになる。

数学関数 (maths.pm モジュール)
加減乗除算のほか、abs・tan・sin・cos・exp・log・rand などが使用可能。どういうときに使うと便利なんだろうか。
printf("1+2=%d\n", add(1, 2));
printf("1+2+3+4=%d\n", add(1, 2, 3, 4));
printf("5-2=%d\n", sub(5, 2));
printf("3*4=%d\n", mul(3, 4));
printf("8/2=%d\n", div(8, 2));
printf("pi=%d\n", M_PI);
printf("e=%d\n", M_EI);
>> コマンド cpp *

find ファイルを検索する。

基本的には
% find 検索開始ディレクトリ 検索条件 コマンド
という書式で使う。FreeBSD・Linux など一部の find では、
% find /usr
と、検索開始ディレクトリのみを指定すると、コマンドとして -print が指定されたものとして動作する。また、Linux の find では
% find
と検索開始ディレクトリの省略も可能。この場合カレントディレクトリが検索開始ディレクトリとみなされる。

注意
find は、OS によって使用可能なオプションが大きく異なる。最も高機能な find は、Linux で使用されている GNU find であろう。*BSD の find も、GNU find の機能を積極的に取り込んでいる。一方、Solaris や HP-UX の find は、ここにあげたオプションの半分以上は使用できない。使っている OS のマニュアルでの確認を忘れずに。

検索開始ディレクトリ
検索を開始する起点のディレクトリを指定する
% find /foo/bar -type f -print
⇒ /foo/bar 以下の全ファイルの一覧を表示
% find . -type f -print
⇒ カレントディレクトリ以下の全ファイルの一覧を表示
検索開始ディレクトリは複数指定することも可能である。
% find /usr/local /usr/bin /usr/sbin -type f -print
⇒ /usr/local と /usr/bin と /usr/sbin 以下の全ファイルを表示

検索条件
-name file
検索するファイルを指定。ワイルドカードとして *・?・[・] を使用することが可能だが、その場合は "" などで囲むこと。ファイル名のみが検索対象であることに注意。カレントディレクトリ以下に
abc.txt
xxx/
xxx/abc.txt
abc/
abc/def.txt
というファイル・ディレクトリがあるとき、
% find . -name "*abc*"
とすると、abc.txt と abc/ と xxx/abc.txt はマッチするが、abc/def.txt はマッチしない。
-iname file
検索するファイル名を指定。大文字小文字を区別しない以外は -name と同じ。
-regex reg
パスを含むファイル名全体が正規表現 reg にマッチするものを検索する。-name と異なり、検索対象がパスも含むことに注意。また、「〜を含む」ではなく、「全体がマッチする」という条件であることにも注意。例えば
% find . -regex "abc"
は絶対にマッチしない。なぜなら、カレントディレクトリに abc というファイルがあった場合は「./abc」と出力されるが、これは -regex で指定した「abc」とマッチしないからである。この場合は
% find . -regex ".*abc.*"
としなければならない。
-iregex reg
大文字小文字を区別しない以外は、-regex と同じ。
-atime [+-]n
n日前にアクセスされたファイル。
-atime 4 4日前にアクセスされたファイル
-atime +4 5日以前にアクセスされたファイル
-atime -4 3日以内にアクセスされたファイル
-ctime [+-]n
n日前にファイルステータスが変更されたファイル
-ctime 4 ちょうど4日前にファイルステータスが変更されたファイル
-ctime +4 5日以前にファイルステータスが変更されたファイル
-ctime -4 3日以内にファイルステータスが変更されたファイル
-mtime [+-]n
n日前に修正されたファイル
-mtime 4 ちょうど4日前に修正されたファイル
-mtime +4 5日以前に修正されたファイル
-mtime -4 3日以内に修正されたファイル
-group グループ名
指定のグループに属するファイル
-inum inode 番号
指定の inode のファイルまたはディレクトリ。inode は ls -i で確認できる。inode はファイルシステムごとの通番のような番号なので、複数のファイルシステムにまたがった場合は同じ inode が存在する可能性があることに注意。

例えば、/・/usr・/home・/var という 4つのファイルシステムがマウントされている場合、
% find /usr -inum 100
であればファイルが 1つに特定できるが、
% find / -inum 100
とすると /・/usr・/home・/var それぞれの inode が 100 であるファイルが表示される可能性がある。
>> コマンド ls *
-newer file
ファイル file よりタイムスタンプが新しいファイル・ディレクトリを検索。タイムスタンプ比較用ファイルをあらかじめ作成し、touch コマンドを使ってタイムスタンプを変更し、そのファイルと比較するとよい。

逆に、「〜より古い」という条件で検索したい場合は、条件の否定を使う。
% find . ! -newer file -print
>> コマンド touch *
-maxdepth n
検索対象を n 階層に制限する。
% find / -maxdepth 0
/
⇒ 0 階層目 (指定した検索開始ディレクトリ) でストップ

% find / -maxdepth 1
/
/dev
/etc
(略)
⇒ 1 階層目でストップ。ただし 0階層目の / も表示されていることに注意。

% find / -maxdepth 2
/
/dev
/dev/network
(略)
/etc
/etc/defaults
(略)
⇒ 2 階層目でストップ。ただし 0・1階層目も表示されていることに注意。
-mindepth n
n 階層以内のファイル・ディレクトリを表示しない。上位のディレクトリを対象外にしたい場合に有用。
% find / -mindepth 1
/dev
/dev/network
/dev/geom.ctl
(略)
⇒ / が表示されていないことに注意

% find / -mindepth 2
/dev/network
/dev/geom.ctl
(略)
⇒ / と /dev が表示されていないことに注意

-mindepth は、-maxdepth と組み合わせると有用である。
% find /usr -maxdepth 1 -mindepth 1 -type d
⇒ /usr 直下にあるディレクトリのみを表示。
-prune
それ以上ディレクトリを降りない。特定のディレクトリ以下を除外する場合に有用。
% find . -prune -print
.
⇒ 単体で使用しても意味がない。
% find . -type d -name CVS -prune -o -print
⇒ CVS/ 以下を除外する。
% find /usr/* -type d -prune
⇒ /usr 直下にあるディレクトリのみを表示
実際は -prune はディレクトリ以外にも効果があるので、
% find . -name "*.txt" -prune -o -print
⇒ *.txt というファイルを除外する。
という使い方もできるが、これは
% find . ! -name "*.txt"
と同じである。

-type * ファイルの種類
b ブロックデバイス
c キャラクタデバイス
d ディレクトリ
f ファイル
l シンボリックリンク
p 名前付きパイプ
s ソケット (UNIX ドメインソケット)
D Door (Solaris のみ)
-size [+-]n[c]
ブロックサイズまたはファイルサイズで検索。「-size 100」だとブロックサイズとみなし、「-size 100c」などと末尾に c をつけるとファイルサイズとみなす。
% find . -size 100c
⇒ ファイルサイズがちょうど 100 バイトのファイル・ディレクトリを検索
% find . -size +100c
⇒ ファイルサイズが 101 バイト以上のファイル・ディレクトリを検索
% find . -size -100c
⇒ ファイルサイズが 99 バイト以下のファイル・ディレクトリを検索

% find . -size 4
⇒ ブロックサイズが 4 のファイル・ディレクトリを検索
% find . -size +4
⇒ ブロックサイズが 5 以上のファイル・ディレクトリを検索
% find . -size -4
⇒ ブロックサイズが 3 以下のファイル・ディレクトリを検索
各ファイルのブロックサイズは ls -s で参照できる。
>> コマンド ls *
条件の結合・否定など
-a または -and
検索条件を AND で結ぶ。
% find . -name abc -and -type d
⇒ abc という名前のディレクトリを検索
ただし、複数の検索条件を並べて書けば AND として扱われるので、上記コマンドは
% find . -name abc -type d
と同じ。
-o または -or
検索条件を OR で結ぶ。
% find . -name abc -or -type d
⇒ abc という名前のファイル・ディレクトリか、あるいはディレクトリを検索
! または -not
他の条件の前に付けて、条件を否定する。-not は一部の find でしか使えない。
% find . ! -name \*.txt -print
⇒ 拡張子が .txt で *ない* ファイル・ディレクトリ
% find . -not -newer target.txt -print
⇒ target.txt とタイムスタンプが同じか、あるいは古いファイル・ディレクトリ
コマンド
-print 検索ファイルを表示
-ls 検索ファイルを詳しく (ls -l と同じように) 表示
より正確に言うと、行頭に inode と使用ブロックサイズが表示されるため、ls -lis と同じである。
-exec 検索ファイルを引数としてコマンドを実行
-ok -exec と同じだが、実行する際に確認を求める


% find / -name .cshrc -print
⇒ ルートディレクトリ以下の .cshrc を検索してフルパスを表示する
% find /usr/local -name file\* -ls
⇒ /usr/local 以下の file* を検索して詳細な情報を表示する
% find . -name \*~ -exec rm {} \;
⇒ カレントディレクトリ以下の *~ をリストアップして「rm 検索したファイル名」を実行する。{}の場所には検索したファイル名が入る。; はコマンドの終了を表すが、シェルに「;」を解釈させず、find へ「;」を渡すためにエスケープしてある。また、「{}」と「\」の間には必ずスペースを空けなくてはならない。
% find . -name \*~ -print -exec rm {} \;
⇒ コマンドは複数個指定できる。
% find . -name \*~ -exec ls {} \; -exec rm {} \;
⇒ (この例はあまり意味はないが) -exec を複数個指定してもよい。

他ユーザのディレクトリを検索する場合、読み込み権限のないディレクトリは permission denied と表示され、出力が見にくくなる。csh・tcsh なら
% (find / -name hoge\* -print >/dev/tty ) >& /dev/null
とすることで、標準エラー出力のみを捨てることができる。sh・bash なら
% find / -name fvwm\* -print 2>/dev/null
とすればよい。
>> 用語集 リダイレクト *

locate コマンドの方が高速にファイルを検索できる。locate コマンドが使えるなら、まずそちらを使うべし。

ソースの中から文字列「hogehoge」を検索するには
% find . -name \*.c -exec grep hogehoge {} \;
とすればよいが、これでは *.c のファイルの数だけ grep コマンドが実行され、時間がかかる。そういう場合は
% find . -name \*.c -print | xargs grep hogehoge
とすればよい。もっときっちりやるなら
% find . -name \*.c -print0 | xargs -0 grep hogehoge /dev/null
なのだが、詳しくはマニュアルを読んでくれい。
>> コマンド locate *   xargs *   tree *

finger 現在ログインしているユーザ名を表示。ユーザの個人情報を表示

引数なしで起動すると現在ログインしているユーザ名を表示する。ユーザ名を指定すると、そのユーザの個人情報を表示する。

% finger
⇒ 現在ログインしているユーザの一覧を表示
% finger username
⇒ ローカルホストのユーザ username についての情報を表示
% finger -l username
⇒ ローカルホストのユーザ username についての詳細な情報を表示
% finger username@anotherhost
⇒ anotherhost のユーザ username についての情報を表示。この場合、anotherhost で fingerデーモンが動いている必要がある。

GNU fingerd を使っている場合、ホームディレクトリに ~/.nofinger というファイルを作っておくと、そのユーザが存在しないかのように扱われる。

大学などでは fingerd が動いているところもあるかもしれないが、一般のプロバイダではまず fingerd は不要なサービスとして止められているだろう。
>> 設定ファイル ~/.nofinger *   ~/.plan *   ~/.project *   users *   who *

flame フラクタル画像を描く

>> コマンド xscreensaver *

flex 字句解析パーサ生成プログラム

lex の上位互換プログラム。構文解析器の bison と組み合わせて使用されることが多い。bison とは異なり、flex は GNU のプロダクトではなく、GPL で配布されてもいない。
>> コマンド lex *   yacc *   bison *
>> 読み方 flex *

fold テキストを一定幅に整形する(パイプ)

指定した文字数より長い行を切り詰める。
% ls -l | fold -w 40
⇒ 1行を 40文字に整形
fold はタブを認識しないので、タブを含むテキストは expand で前処理する必要がある。また、FreeBSD (FreeBSD2.2.6で確認) の /usr/bin/fold は日本語をうまく扱えなかったので、日本語を含む文章は nkf の -f オプションを使うとよい。
>> コマンド cut *   expand *   nkf *

for 指定されたコマンドを一括して実行する。sh・bash の内部コマンド

指定されたファイルに対して、一連のコマンドを実行する。例えば複数のファイルの文字コードを変換したい場合、
% for i in file1 file2 file3
> do
> nkf -e < $i > tmp
> mv tmp $i
> done
とすると、file1、file2、file3 が順にシェル変数 $i にセットされ、nkf と mv が実行される (この例では qkc を使えば文字コードの一括変換ができるのだが)。必ず前後を do と done で挟むこと。また、
% foreach i in *.txt /tmp/hoge/a??
などとメタキャラクタを使うこともできる。

DOS でいうところの
% copy *.txt *.txt.bak
を行うには
% for i in *.txt
> do
> cp $i $i.bak
> done
とする。拡張子の一括変換は
% for i in *.txt
> do
> cp $i ${i%.txt}.html
> done
とする。また、for は ; で区切ることで1行で書くことができる。
% for i in file1 file2 file3 ; do nkf -e < $i > tmp ; mv tmp $i ; done

for 文は sh・bash の内部コマンドである。csh・tcsh には foreach が用意されている。なお、tcsh の foreach の中で実行したコマンドはヒストリでさかのぼれないのに対して、bash の for は複数行で記述しても、ヒストリでさかのぼると ; で区切った1行の文字列として表示してくれる。bash の勝ち。
>> コマンド foreach *
>> 用語集 シェルスクリプト *

foreach 指定されたコマンドを一括して実行する。csh・tcsh の内部コマンド

指定されたファイルに対して、一連のコマンドを実行する。例えば複数のファイルの文字コードを変換したい場合、
% foreach i ( file1 file2 file3 )
foreach? nkf -e < $i > tmp
foreach? mv tmp $i
foreach? end
とすると、file1、file2、file3 が順にシェル変数 $i にセットされ、nkf と mv が実行される。
% foreach i ( *.txt /tmp/hoge/a?? )
などとメタキャラクタを使うこともできる。

DOS でいうところの
% copy *.txt *.txt.bak
を行うには
% foreach i ( *.txt )
foreach? cp $i $i.bak
foreach? end
とする。拡張子の一括変換は
% foreach i ( *.txt )
foreach? cp $i $i:s/.txt/.html/
foreach? end
とすればよい。

シェル変数への代入時は $ を付けてはいけないことに注意。つまり
% foreach $i ( ... )
はエラーになる。

foreach は、csh・tcsh の内部コマンドである。sh・bash の場合は for が用意されている。
>> コマンド for *
>> 用語集 シェルスクリプト *

freebsd-update FreeBSD のバイナリ更新を行う。Windows Update のようなもの

FreeBSD のバイナリ更新を行う。Windows Update のようなお手軽ツール。

まず、port か package から freebsd-update をインストールする。

そして設定ファイルを用意する。
# cd /usr/local/etc/
# cp freebsd-update.conf.sample freebsd-update.conf
⇒ ここではデフォルトの設定ファイルをそのまま使用している

これで準備は完了。まず、fetch でバイナリパッチを取得する。
# /usr/local/sbin/freebsd-update fetch
Fetching updates signature...
Fetching updates...
Fetching hash list signature...
Fetching hash list...
Examining local system...
Fetching updates...
/boot/kernel/kernel...
/usr/bin/fetch...
Updates fetched
To install these updates, run: '/usr/local/sbin/freebsd-update install'

どのファイルが更新されるか確認したら、install を行う。
# /usr/local/sbin/freebsd-update install
Backing up /boot/kernel/kernel...
Installing new /boot/kernel/kernel...
Backing up /usr/bin/fetch...
Installing new /usr/bin/fetch...
これでおしまい。簡単なものである。

freebsd-update で指定できる主なコマンド
fetch
バイナリパッチを取得する。インストールは行われない。
install
fetch で取得しておいたパッチをインストールする。
cron
fetch を行い、もしバイナリパッチが提供されていれば root 宛にメールを送信する。提供されていなければ何もしない。これを cron に仕込んでおくと、メールが届いたときだけ freebsd-update install を手動で実行すればよいわけである。
rollback
install したパッチを削除する。何度も rollback することで、どんどん以前の状態にさかのぼることができる。

注意点
  • freebsd-update はセキュリティ関連の脆弱性を修正するための仕組みであって、FreeBSD を最新リリースに保つための仕組みではない。例えば FreeBSD 5.1-RELEASE で freebsd-update しても、FreeBSD 5.2-RELEASE に更新されるわけではなく、あくまで 5.1-STABLE を追っかけているに過ぎない。
  • freebsd-update はインターネット経由でバイナリパッチを取得するため、インターネットに接続しておく必要がある。なお、fetch コマンドを使って HTTP 経由でファイルを取得するので、必要であれば proxy の設定などを行っておくこと。
  • バイナリパッチであるため、カーネルや基本配布物を手元でコンパイルしてしまうと、freebsd-update は動作しない。
  • 適用するパッチを選択することはできない。freebsd-update を使って全ての基本配布物を最新の状態に保つか、freebsd-update を使わないか、のいずれかを選択しなければならない。
  • 更新対象となるのは FreeBSD の基本配布物のみである。つまり /bin・/usr/bin・/usr/sbin は更新対象だが、/usr/local/bin や /usr/local/sbin などの ports・packages は更新の対象とならない。
  • 静的にリンクしている ports・packages のプログラムに注意。例えば libc の関数に脆弱性が発見されたとする。その結果、以下のファイルは freebsd-update によって更新される。
  • 静的ライブラリ /usr/lib/libc.a
  • libc.a を静的にリンクしている基本配布物のコマンド
  • 動的ライブラリ /usr/lib/libc.so
しかし静的ライブラリ /usr/lib/libc.a を静的にリンクしている ports・packages のコマンドがその関数を使用していた場合、脆弱性は残ったままとなる。このようなときは portupgrade -f で ports・packages を再インストールするのがお手軽。
  • カーネルが更新された場合はリブートを忘れずに。カーネルモジュールが更新された場合は、kldstat -v でカーネルが使用中かどうかを確認すること。もし使用中であればモジュールの機能を使用しているサービスを止めてから kldunload・kldload して再度ロードしなおすか、あるいはリブートすること。


freebsd-update は一見「バイナリを比較して、もし異なっていれば配布する」という単純な作業をしているだけに見えるが、そう簡単ではない。

まず、FreeBSD のビルド時に生成されるバイナリにタイムスタンプが埋めこまれるものがある。これは同じソースから二回ビルドを行い、異なる部分を比較の対象外とすることで解決している。中には日付を文字列でバイナリに埋め込んでしまうものがあるが、「March」と「February」のように長さが異なってしまうため、ビルドのたびにバイナリサイズが変わってしまう。また、ビルドのたびにランダムなデータを生成するものもある。このようなイレギュラーなファイルは比較対象外とするなど、結構大変なのだ。

ちなみに当ページ管理人は freebsd-update を愛用している。

from 到着したメールの送り主一覧を表示

未読メールの一覧を表示する。プログラム自体は単純で、メールスプール (/var/mail/$USER) を読み込み、From: ヘッダの行を表示するだけである。なお、POP (他のサーバにメールスプールがあるということ) には対応していない。
% from
From foo@example.co.jp Sat Jun 24 12:57:21 2005
From bar@mail.example.net Sat Jun 25 09:27:08 2005
From bar@mail.example.net Sat Jun 25 23:57:44 2005

オプション
-f メールスプールを指定する。デフォルトは /var/mail/$USER
>> コマンド mail *   xbiff *   xpbiff *

fsck ファイルシステムの矛盾の検出・修復

UNIX が起動したとき、システムは /etc/fstab を参照しながら mount コマンドを用いて自動的にファイルシステムをマウントする。OS を終了する際は、umount コマンドが自動的に実行され、ファイルシステムをアンマウントする。

もしアンマウントせずに OS を終了した場合(例えば PC の電源をいきなり切ったとか)、次回の OS の起動時には自動的に fsck コマンドが実行される。大抵の場合はこの自動実行される fsck がファイルシステムを修復してくれるが、たまに自動修復に失敗することもある。

fsck を手動で実行する場合は、たくさんの質問が聞かれるが、UNIX に精通していないと質問の意味が理解にしくい。その場合 fsck -y で実行すると、全ての質問に yes と答えたことになる。
>> コマンド mount *

fstat 現在オープンしているファイルの情報を表示

現在、どのプロセスが、どのファイルを参照/書き込みしているかを表示する。umount コマンドを実行して Device Busy エラーになったとき、どのプロセスがアクセスしているのかを調べるのに便利。

ファイル filename に現在アクセスしているプロセスを調べるには
% fstat filename
USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W NAME
foo      jless        373    4 /usr     729624 -rw-r--r--    5867  r  filename
とする。これによると、ユーザ foo が実行しているプロセス jless (プロセス番号 373) が、ファイル filename (i-node 729624、パーミッション 644、ファイルサイズ 5867) を、読み込みモード (R/W=r) でオープンしていることがわかる。

vi や emacs・mule などのエディタでファイルを読み込んだ場合は、ファイルをオープンしてバッファに読み込んだ後 クローズしてしまう。よって、これらのエディタを使って、どのファイルにアクセスしていることを知るのは難しい (ちょうどファイルをオープンしている最中に fstat を実行しなければならない)。一方、tail -f や more・less はずっとファイルをオープンし続けるので、fstat で容易に調べることができる。

オプション
-p PID 指定した PID のプロセスが開いているファイルのみを表示
-u user 指定したユーザのプロセスが開いているファイルのみを表示
-f 指定したファイル・ディレクトリの属するファイルシステムの情報を表示
% fstat -f /usr/
⇒ /usr が属するファイルシステムのファイルをオープンしているプロセス一覧を表示

fstat コマンドは BSD 系にしかない。SystemV では fuser という同様のコマンドがある。Linux では標準で lsof というコマンドがインストールされている場合が多い。
>> コマンド fuser *   lsof *   umount *

ftp ファイル転送ユーティリティ

ローカルホストから別のホストに接続し、ファイルを転送 (置きにいく/持ってくる) することができる。

anonymous FTP サイトからファイルをダウンロードする場合は、ユーザ名に「anonymous」か「ftp」、パスワードに自分のメールアドレスを指定する。たまに「ftp」ではダメで、「anonymous」と入力しなければならない FTP サーバもある。

また、クライアントのマシンが逆引きできない (IP アドレスからホスト名への変換ができない=DNS の設定がされていない) とログインさせてくれない anonymous FTP サイトもある。

ftp://ftp.hoge.com/pub/sample/test.tgz をダウンロードする場合の操作例を以下に示す。
% ftp
ftp> open ftp.hoge.com (FTPサイトに接続)
Connected to ftp.hoge.com
220 ftp.hoge.com FTP server (UNIX(r) System V Release 4.0) ready
User (ftp.hoge.com:(none)) : ftp(あるいはanonymous)
331 Password required for ftp
Password: 自分のメールアドレス(適当に入力しても問題ないが、マナーとして正しいメールアドレスを入力する)
230 User ftp logged in
ftp> ls (カレントディレクトリのファイル・ディレクトリを表示)
(ファイル・ディレクトリ一覧が表示される)
ftp> cd pub/sample
ftp> get test.tgz
ftp> bye (FTP終了)

主要コマンド一覧
open リモートホストに接続
close リモートホストへの接続を切断
user パスワードを間違った場合は、user コマンドで再度ログインし直すことができる。
ls ファイル・ディレクトリ一覧を表示
メタキャラクタを使って、
ftp> ls *.txt
などと、拡張子が txt のファイル一覧だけを表示することもできる。
cd リモートホストのカレントディレクトリを指定したディレクトリに変更。
引数なしで実行すると、(リモートの) ホームディレクトリに移動する
lcd ローカルホストのカレントディレクトリを指定したディレクトリに変更。
引数なしで実行すると、(ローカルの) ホームディレクトリに移動する
pwd リモートホストのカレントディレクトリを表示
bye ftpを終了
get ファイルをリモートホストからローカルホストに転送する
put ファイルをローカルホストからリモートホストに転送する
ftp> pwd (リモートのカレントディレクトリは /home/remote)
257 "/home/remote" is current directory.
ftp> !pwd (ローカルのカレントディレクトリは /home/local)
/home/local
ftp> get file1
⇒ /home/remote/file1 を /home/local/file1 に転送する。
ftp> get file1 new-file1
⇒ /home/remote/file1 を /home/local/new-file1 に転送する。
ftp> get dir/file1
⇒ /home/remote/dir/file1 を /home/local/dir/file1 に転送する。この際、ローカルにも /home/local/dir/ というディレクトリが存在しないとエラーになる。
ftp> get dir/file1 new-file1
⇒ /home/remote/dir/file1 を /home/local/new-file1 に転送する。
mget 複数ファイルをget (メタキャラクタ使用可)
mput 複数ファイルをput (メタキャラクタ使用可)
get/putコマンドは、一度に1つのファイルしか転送できないが、mget/mput を使うと、一度に複数のファイルを転送できる。デフォルトでは、ファイルを1つ転送する前に、ユーザに確認を求めてくる。
ftp> ls *.gz
-rw-r--r-- 1 user group 2151 Jun 28 00:20 file1.tar.gz
-rw-r--r-- 1 user group 1716 Jun 28 00:20 file2.tar.gz
-rw-r--r-- 1 user group 3828 Jun 22 23:19 file3.gz
ftp> mget *.gz
mget file1.tar.gz? (ここでyかEnterを押すと転送する)
mget file2.tar.gz? (ここでyかEnterを押すと転送する)
mget file3.gz? (ここでyかEnterを押すと転送する)
毎回の確認にいちいち答えるのが面倒な場合は、prompt コマンドを使えばよい。
ftp> ls *.gz
-rw-r--r-- 1 user group 2151 Jun 28 00:20 file1.tar.gz
-rw-r--r-- 1 user group 1716 Jun 28 00:20 file2.tar.gz
-rw-r--r-- 1 user group 3828 Jun 22 23:19 file3.gz
ftp> prompt
Interactive mode off.
⇒ ユーザに確認しないモードになった
ftp> mget *.gz
⇒ 確認なしで3つのファイルが転送される
prompt mget,mput 使用時に各ファイルを転送するかどうか、毎回ユーザの確認を求める/求めない (トグル)。
glob mget,mput使用時にメタキャラクタを展開する/展開しない (トグル)
hash ファイルの転送状況を表示/非表示 (トグル)。
大きなファイルを転送する際は、hashをONにして、どこまで転送が終ったかがわかるようにするとよい。
ascii テキストモードで転送。改行コードを適切に変更する。
binary バイナリモードで転送。扱うファイルがテキスト以外ならこれが必要
なお、ローカルもリモートも UNIX ならば、自動的に binary モードに設定されるので、ascii/binary を気にする必要はない。
status 現在の設定を表示 (prompt など)
passive パッシブモードに切り替え
-p オプションの項を参照。
!command ローカルホストでコマンドを実行
例えば !pwd とすることで、ローカルのカレントディレクトリを表示させることができる。

オプション
-n コマンドを標準入力から読む
例えば ftpcommand.dat というファイルに
open ftp.hogehoge.ac.jp
user username passwd
binary
cd lib
lcd lib
get sample
put test
bye
などと書いておき、
% ftp -n < ftpcommand.dat
とすると、自動的にファイルのやりとりが行われる。プレインテキストにパスワードを書いておくことになるので、chmod 600としておくこと。ほかにも自動で ftp するには~/.netrc に記述しておく方法がある。
>> 設定ファイル ~/.netrc *
-d デバッグモード
FTP サーバとやりとりするプロトコルの内容を表示。http://X68000.q-e-d.net/~68user/net/ftp-1.html
-p パッシブモード
ftp を実行した直後に passive とタイプするのと同じである。

知っておくと便利な機能
  • ls . |command とすることで、任意のコマンドに出力を渡すことができる。
例えば、ls の出力が画面内に収まりきらない場合は
ftp> ls . |more
とすればよい。空白の場所に注意。「.」のファイル一覧を「|more」に渡す (=パイプで渡す) わけである。

最近の ftp コマンドに付いている便利な機能
以下の機能は少なくとも FreeBSD・NetBSD・OpenBSD 標準の ftp コマンドに備わっている。
  • Ctrl-D・TAB を押すことで、emacs・tcsh 風の (ローカル・リモートとも)ファイルの補完ができるようになっている。
  • Ctrl-p・Ctrl-n でヒストリを利用できる
>> コマンド fetch *   wget *   ncftp *   rcp *   xarchie *   xftp *

funzip ZIP アーカイブを標準入力から読み込み、伸張 (解凍)・展開する

funzip は、標準入力から ZIP アーカイブを読み込み、伸張 (解凍)・展開するコマンドである (funzip の f は filter)。unzip コマンドは標準出力からの入力をサポートしていないため、別のコマンドになっている。

[利用例]
% dd if=/dev/nrst0 | funzip | tar xf -
テープから読み込んだデータを標準入力から読み込んで伸張し、tar に渡す。

zip の伸張に関する詳細な説明は unzip を参照。
>> コマンド unzip *   zip *

fuser ファイル・ソケットを使用しているプロセスを表示 (Solaris・Linux)

TCP のポート 80 を使用しているプロセスを調べる。
# fuser -vn tcp 80
                     USER        PID ACCESS COMMAND
80/tcp               root        212 f....  httpd
                     root       6113 f....  httpd
                     root       6114 f....  httpd

FreeBSD では fuser ではなくsockstat を使うこと。
>> コマンド sockstat *   fstat *   lsof *

fvwm 複数の仮想画面を持つウィンドウマネージャ

ウィンドウマネージャの役割は各ウィンドウを管理することである。ウィンドウには枠やタイトルがあり、マウスをクリックすることでそのウィンドウがアクティブになったり、ウィンドウの移動ができる。ルートウィンドウ(背景)でマウスをクリックするとメニューが表示される。これらの機能はすべてウィンドウマネージャのおかげで実現されている。
ためしに、~/.xsession の fvwm (あるいは twm) という行をコメントアウトして、最後の行に kterm とだけ書いてみると、ウィンドウの枠やタイトルがなくなり、移動やリサイズができなくなる。メニューもでなくなる。終了するには最後に起動した kterm で exit としなければならない。

設定ファイルは~/.fvwmrc。
>> コマンド afterstep *   twm *   fvwm2 *   fvwm95-2 *   enlightenment *

fvwm2 fvwmのバージョン2。

設定ファイルは~/.fvwm2rc。~/.fvwmrc との互換性はないので注意。fvwm に比べてメモリを食うが、実装の仕方がきれいになった(らしい)。システム付属の設定を使うには、
% cp /usr/X11R6/lib/X11/fvwm/system.fvwmrc ~/.fvwmrc
として、~/.xsession (あるいは ~/.xinitrc) の最後に exec fvwm と書けばよい
>> コマンド afterstep *   twm *   fvwm *   fvwm95-2 *   enlightenment *

fvwm95-2 Windows95 風のウィンドウマネージャ。

システム付属の設定を使うには、
% cp /usr/X11R6/lib/X11/fvwm95-2/system.fvwmrc ~/.fvwm2rc95
として、~/.xsession (あるいは ~/.xinitrc) の最後に exec fvwm95-2 と書けばよい。
>> コマンド afterstep *   twm *   fvwm *   fvwm2 *   enlightenment *

gas GNUアセンブラ

FreeBSD の場合は、システム標準のアセンブラ as が gas になっている。
>> コマンド as *

gawk GNU awk。日本語も扱える。

>> コマンド awk *

gcc GNU C/C++ コンパイラ

GNU が作成している C/C++ コンパイラ。FreeBSD、Linux などは標準の C コンパイラが gcc になっている (ccとgccはハードリンクされている)。Solaris など商用マシンでも gcc の重要度は高く、OS 標準のコンパイラではコンパイルできず、gcc を使わないといけないソフトウェアも多い。

使い方
エディタで適当なファイル、例えば sample.c に
#include <stdio.h>
main(){
printf("hello world.\n");
}
と書いて、
% gcc sample.c
とすると、a.out というコンパイル済のバイナリファイルが作成される。実行すると
% ./a.out
hello world.
となる。*.cc という拡張子は C++ のソースとして扱われる。

内部動作
gcc の内部では
1. プリプロセッサ /usr/libexec/cpp
前処理用プログラム。#include、#define などを処理。
2. コンパイラ /usr/libexec/cc1
C 言語をアセンブラに変換。
3. アセンブラ /usr/bin/as
アセンブラをマシン語に変換。出力はオブジェクトファイル(*.o)。
4. リンカ /usr/bin/ld
オブジェクトファイルとライブラリをリンク (結合処理) する。
が順に呼ばれる。-E、-S、-c オプションで、任意の段階で処理を止めることができる。

オプション
-E プリプロセス後終了。コンパイルをしない。
プリプロセッサの出力を標準出力に書き出す。#include や #define などがプリプロセッサによって処理される。#ifdef 〜 #endif が多くて読みにくいソースは -E オプションを使うとよい。なお、インクルードファイルの読み込み部分で多くの空行が挿入されるので、cat コマンドの -s オプション (連続する空行を 1行にまとめる) を使って
% gcc -E foo.c | cat -s | less
などとするのがお勧め。
-S コンパイル後終了。アセンブルをしない。
-c アセンブル後終了。リンクを実行しない。
*.o というオブジェクトファイルを生成した時点でストップする。

-g デバッグ用の情報を保存する
gdb などのデバッガを使う場合に有用な情報をバイナリに残しておく。
>> コマンド strip *
-static 静的にリンクする
通常、printf(3) を使用しているプログラムをコンパイルすると、
% gcc a.c
% ldd ./a.out
./a.out:
libc.so.4 => /usr/lib/libc.so.4 (0x28066000)
というふうに、実行時に共有ライブラリを動的にリンクするようなバイナリが生成される。この例では a.out は共有ライブラリ libc.so.4 を使用するようになっており、実行時に libc.so.4 が存在しないと a.out は実行できない。

一方、-static オプションを付けてリンクすると、必要なライブラリがバイナリにリンクされ、バイナリ単体で実行が可能になる。
% gcc a.c
% ldd a.out
ldd: a.out: not a dynamic executable

ただし、静的リンクをすると
  • バイナリサイズが増加する
  • 複数のプロセス間で実行時にライブラリのメモリを共有できない(共有ライブラリにしておけば、テキスト領域の分だけメモリを共有できる)
  • ライブラリにバグがあったら、全バイナリをコンパイルしなおす必要がある
という欠点がある。
>> コマンド ldd *
-o 生成する実行ファイル名を指定。-o で指定しないと a.out というバイナリが生成される。
% gcc -o bar foo.c
⇒ 生成されるバイナリは bar となる。
% gcc foo.c
⇒ デフォルトのファイル名である、a.out が生成される。
-v バーボーズモード。
マクロ、インクルードパス、プリプロセッサ、アセンブラ、リンカに渡すオプションを全て表示する。
-pipe テンポラリファイルを作らず、パイプで処理する。
コンパイルにかかる時間が短縮されるが、より多量のメモリが必要。
-ansi ANSI C に準拠する。
GNU C 独自の拡張機能である asm・inline・typeof などが使えなくなる。
-trigraphs ANSI C のトライグラフを認識する
-traditional 伝統的な C の文法を認識する
-w 警告 (warning) を表示しない
-W... 各種の警告 (warning) を表示するかどうか設定する
例えば -Wimplicit-function-declaration や -Wswitch など、数十種類の -W... オプションがある。全ての -W... を有効にするには -Wall を使う。
-Wall -Wスイッチで指定できる全ての警告 (warning) を表示する
なるべく -Wall オプションを付けても警告 (warning) が出ないようなコードを書くべき。
-Wl, リンカに渡すオプションを定義する。
非常に分かりづらいが、警告系の -W オプションとは無関係。例えば
% gcc -Wl,-rpath=. hoge.c
とすると、リンカに「-rpath=.」というオプションが渡る。
-O 最適化したコードを生成する。
実行速度が速くなったり、バイナリのサイズを減らすことができる。-O2 -O3 などと数字を与えることで、最適化の段階を指定することができる。数字が大きいほど賢い最適化を行う。最適化を行うとコンパイルに時間がかかるので、デバッグ終了後に行うとよい。
-D マクロを定義
% gcc -DHOGE foo.c
とするのは、foo.c の先頭に
#define HOGE 1
と書いたことと同じである。また、
% gcc -DHOGE=10 foo.c
% gcc -DHOGE=\"string\" foo.c
も同様に
#define HOGE 10
#define HOGE "string"
を加えたのと同じである。foo.c の中でマクロ HOGE の定義が行われていたとしても、-D オプションで指定した値が有効になる。-U オプションでマクロを無効にできる。

自作のソースをコンパイルするときはあまり使わないだろうが、一般に配布されているプログラムは、多くの環境でコンパイルできるようにするため、#ifdef 〜 #else 〜 #endif が山のように埋め込まれている。そのままコンパイルできれば問題ないのだが、もしコンパイル途中にエラーで終了した場合は、あれこれ悩みながら -D オプションでマクロを設定することになる。

また、データの最大数が
#define MAX_DATA 1000
とマクロで定義されているときや、〜という機能を有効にするかどうかをマクロで決定する場合は、それぞれ
% gcc -DMAX_DATA=3000 ....
% gcc -DENABLE_HOGE ....
とすることで、ソースを書き換えることなくコンパイルできる。

ただし、機能のオン・オフや、インストールするディレクトリなどは Makefile を書き換えたり、make の引数でマクロを設定したり、configure のオプションで指定することの方が多い。まずはプログラムに付属するインストールマニュアルを熟読すること。

-U マクロを無効化する
% gcc -UHOGE foo.c
とすると、foo.c の中のマクロ HOGE が無効になり、
#ifdef HOGE
が偽になる。マクロを設定するには -D オプションを使う。

-I インクルードファイルのパスを指定
インクルードファイルを取り込む場合は、ソースの中に
#include <stdio.h>
#include <sys/stat.h>
#include <X11/Xutil.h>
など書く。インクルードファイルが /usr/include/ 以下にあるなら、-I オプションを指定しなくても
/usr/include/stdio.h、/usr/include/sys/stat.h
がインクルードされる。しかし X11/Xutil.h は実際は /usr/X11R6/include/X11/Xutil.h にあるので、
-I/usr/X11R6/include
と、インクルードファイルのパスを指定しなければならない。
-l ライブラリを指定
例: -lm -lnsl -lX11
例えばソース中で sin() を使った場合、sin() のライブラリを指定しないとリンク時にエラーとなる。sin() のライブラリは /usr/lib/libm.a なので、「libm.a」から「lib」と「.a」を取り除いて「-lm」と指定する。同様に、X Window System のライブラリ関数は、/usr/X11R6/lib/libX11.a で定義されているので「-lX11」とする (ただし -L オプションでライブラリパスの指定が必要)。printf、strlen などの基本的な関数は、全て /usr/lib/libc.a というライブラリに 含まれているが、libc.a は標準でリンクされるので -lc と指定する必要はない。

なお、目的のライブラリ関数が、どのライブラリに入っているかは nm コマンドで探すとよい。
% nm -o /usr/lib/*.a /usr/X11R6/lib/*.a | grep sin
>> コマンド nm *   ar *
-L ライブラリのパスを指定
例: -L /usr/X11R6/lib
上で説明したライブラリのあるディレクトリにパスが通っていなかった場合、そのディレクトリを -L オプションで指定する。例えば X11 関係の関数を使用した場合、/usr/X11R6/lib/libX11.a をリンクする必要があるので -lX11 とする。しかし標準設定では /usr/X11R6/lib がライブラリの検索対象となっていないので、-L /usr/X11R6/lib とする必要がある。

昔は gcc は「GNU C Compiler」の略だったが、 現在は「GNU Compiler Collection」の略になった。C や C++、Objective-C に加え、Fortran・Ada・Java までコンパイルできるらしい。
>> コマンド cc *   as *   cpp *   ld *   ldd *   make *   cflow *   unifdef *   strip *   indent *

gcore 実行中のプロセスのコアを得る

gdb デバッガ

16進数 → 10進数変換
% gdb
(gdb) print 0x1234
$1 = 4660
(gdb) p 0x1234 (print を省略して p でもよい)
$1 = 4660
>> コマンド gcc *

getopt 

ghostview Postscript ファイルのビュアー。

ghostview は gs (ghostscript) の GUI インタフェースである。
>> コマンド gs *   a2ps *   dvi2ps *

gimp 高機能グラフィックツール

プロの使用に耐えられるほど高機能。ただし機能が多すぎる分、ちょっと使ってみて雰囲気を掴もうという初心者には、操作がわかりにくいかもしれない。

当ページ管理人は簡単なバナーを作ろうと思ったが、何をどうすればよいのかわからず、結局 xpaint で作った。
>> コマンド xpaint *

gmake GNU make

GNU が作成した make。Makefile 中での条件分岐などが記述できるようになっている。

Linux では GNU make が標準のため、make というコマンド名でインストールされている(gmake というコマンドはない)。一方、BSD では BSD 版 make が標準となっており、Solaris でも SystemV 系の make が標準である。

*BSD や Solaris では、パッケージで GNU make をインストールできる。この場合はシステム標準の make とかち合わないように、gmake というコマンド名でインストールされる。

GNU make、BSD make、SystemV の make はそれぞれ細かい部分で差があるため、*BSD や Solaris でシステム標準の make を使って失敗した場合は、gmake を使ってみるとよい。
>> コマンド make *

gnuplot グラフ描画プログラム

2次元・3次元に対応したグラフ描画プログラム。

gogo MP3 エンコーダ

正式名称は「午後のこ〜だ」。wave 形式の音声ファイルを MP3 形式に変換する。変換スピードが結構速いので、お勧め。音質については各自で聞き比べてほしい。

音楽 CD から tosha で曲を吸い出し、sox で wave に変換、さらに gogo で MP3 に変換
% tosha -d /dev/cd0c -t 2 -o sample.raw
% sox -t cdr sample.raw sample.wav
% gogo sample.wav sample.mp3

音楽 CD から tosha で曲を吸い出し wave で出力、さらに gogo で MP3 に変換
% tosha -d /dev/cd0c -t 2 -f wav -o sample.wav
% gogo sample.wav sample.mp3

上の例と同じだが、中間ファイルを作らない。
% tosha -d /dev/cd0c -t 2 -f wav -o - | gogo stdin sample.mp3
>> コマンド mpg123 *   sox *   tosha *

grance top のようなものらしい。HP-UX のみ。

各プロセスのメモリ使用量やディスクアクセス・CPU 使用率などを表示できる。HP の売り物らしい。
>> コマンド top *

grdc コンソールに時計を表示

n(数字) n秒間だけ時計を表示する

grep 指定のパターンにマッチする行を表示(パイプ)

あるファイルの中に、指定の文字列を含む行を表示する。例えば、sample.dat の中の「hoge」という文字列を含む行を表示したい場合、
% grep hoge sample.dat
とする。また、
% grep hoge file1 file2 file3
% grep hoge dir/*
などとすると、複数のファイルについて調べることができる。

検索したい文字列には正規表現を使うことができる。例えば
% grep '[a-z]' sample.dat
とすると、a〜z を含む行を全て表示する。ただし、grep はデフォルトでは限定正規表現しか扱えないことに注意 (-E オプションを参照)。

FreeBSD や Linux は高機能版の grep (GNU grep) を標準採用しているが、Solaris などはデフォルトの grep は低機能版で、-e オプションや -E オプションを使うことができない。Solaris の場合、/usr/xpg4/bin/grep が高機能版の grep となっている。

grep の用途はとても広い。
  • /var/log/ にあるログファイルから、特定のメッセージを抜き出す
  • /var/log/ にあるログファイルから、特定の日付のみのログを抜き出す
  • /usr/include/ から、特定のマクロがどこで定義されているか調べる
などなど。grep を使いこなせていないとしたら、その人の UNIX のスキルは知れたものである。ぜひ有効な使い方を覚えてほしい。

-num マッチした文字列の前後 num 行を表示する。
デフォルトは -0。つまりマッチした行のみを表示するということ。
-A num マッチした文字列の後に続く num 行を表示する
-B num マッチした文字列の前の num 行を表示する
-b マッチした文字列のオフセットを表示
-C -2と同じ
-c テキスト中に文字列が出現した回数を表示。
-e 明示的にパターンを指定する。複数個のパターンを指定するときに使う
「rwx」と「r-x」を含む行を検索しようとして、
% ls -l | grep 'rwx' 'r-x'
とすると、grep は 「r-x」というファイルを見付けようとしてエラーになってしまう。こういう場合は
% ls -l | grep -e 'rwx' -e 'r-x'
とすればよい。低機能版の grep には -e オプションは効かないので注意。
-E 拡張正規表現を使う。
デフォルトでは 「?+|{}()」などは普通の文字として扱われてしまうので、「foo」と「bar」を含む行を表示しようとして、
% grep 'foo|bar' sample.txt
としても、'foo|bar' という普通の文字列だと認識されてしまう。
% grep -E 'foo|bar' sample.txt
だと拡張正規表現として扱われるので、うまくいく。低機能版の grep には -E オプションは効かないので注意。grep -E は egrep とほぼ同じである。
>> コマンド egrep *
-F 固定文字列として検索する。
. * ? などのメタキャラクタを指定しても、正規表現としての意味を持たなくなる。grep -F は、fgrep と同じである。
>> コマンド fgrep *
-f file file中の文字列を検索パターンとして使う。
-i 大文字小文字を区別しない。
-l 指定文字列を含むファイル名を表示。
指定の文字列を含むファイルが何個あるか数えるには
% grep -l hoge *.txt | wc -l
とする。
>> コマンド wc *
-L 指定文字列を含まないファイル名を表示。
-n マッチした行の行番号を表示する。
-s エラーメッセージを抑制する(ファイルに対しての permission denied など)
-R ディレクトリを再帰的にたどって、ファイルを検索する。
FreeBSD の grep では使えるが、他の UNIX では -R オプションは使えない場合が多い。
-w ファイル中の指定文字列が独立している場合だけマッチしたものとみなす。
% cat test
sample // 独立した文字列ではないのでマッチしない
samp // 記号や空白でかこまれた文字列はマッチする
samp2 // 数字は記号とみなされない
,samp-
(samp&
samp/
% grep -w samp test
samp
,samp-
(samp&
samp/
-x 指定文字列がそのまま1行にあるものだけマッチしたものとみなす
つまり
% grep -x abc

% grep '^abc$'
と等価。
-v 指定文字列を「含まない」行を表示
-Z 圧縮したファイルを grep する。
% compress file.txt
% grep -Z file.txt.Z
>> コマンド zgrep *

必ず覚えてほしいオプションは、-i、-e、-n、-v である。

現在実行中のプロセスから abc という表示を抜き出すには
% ps ax | grep abc (SystemV 系 UNIX なら ps -ef)
とすればよいが、プロセス実行のタイミングによっては
% ps ax | grep abc
118 ?? Ss 0:00.03 abc
760 p3 R+ 0:00.00 grep abc
と、grep 自身がマッチしてしまうことがある。こういうときは
% ps ax | grep '[ a]bc'
とすればよい。grep '[ a]bc' を実行すると、ps の出力には
760 p3 R+ 0:00.00 grep [ a]bc
となるが、[ a]bc 自体は正規表現と解釈されるので、
760 p3 R+ 0:00.00 grep [ a]bc
の行にはマッチしないわけである。まぁ、単純に
% ps ax | grep abc | grep -v grep
でもよいのだけれど。
>> コマンド fgrep *   egrep *   zgrep *   agrep *   sed *   tr *   find *   xargs *
>> 読み方 grep *

greynetic 長方形をランダムに描く

>> コマンド xscreensaver *

gs ghostscript。PostScript (ポストスクリプト) 形式のファイルを表示する

.ps や .eps などの拡張子を持った PostScript 形式の画像を表示する。

PostScript を別の形式に変換するには convert コマンドを使うとよい。
>> コマンド convert *   a2ps *   dvi2ps *   ghostview *

gzcat 圧縮されたファイルの内容を伸長せずに表示。実行ファイルは gzip と同じ。

zcat は本来 compress で圧縮された *.Z というファイルしか扱えないが、gzcat は gzip で圧縮された *.gz も扱える。ただし、最近の zcat は gzcat と同じ機能を持っている場合が多い。

gzcat は gzip -dc と同じである。
>> コマンド gzip *   zcat *

gzexe 実行ファイルを圧縮して、自己伸長型の実行ファイルを作る。

実行ファイルを gzip で圧縮し、さらに圧縮したファイルの先頭にスクリプトを書き込んで、圧縮してあるのに実行可能なプログラムを作る。

どうやって実現しているかは、圧縮済の実行ファイルを見るとわかる。初めて見ると、結構感動するかも。なお、実行ファイルのサイズを減らしたいなら、strip を使う手もある。
>> コマンド strip *

オプション:
-d 自己伸長型の実行ファイルを元に戻す。
>> コマンド gzip *

gzip 高機能なファイル圧縮・伸長ツール (gunzip)

compress より圧縮率が高く、ファイルの末尾が.gz、.Z、.tgz、.taz のファイルを扱える。オプションなしで起動すると指定のファイルを圧縮し、ファイルの最後に .gz という拡張子をつける。
% ls -l (sample.txt のファイルサイズは 225KB)
-rw-r--r-- 1 user group 225280 Oct 6 07:52 sample.txt
% gzip sample.txt (sample.txt を圧縮)
% ls -l (ファイルサイズが 40KB に減少。ファイル名の最後に拡張子 .gz が付けられる)
-rw-r--r-- 1 user group 40289 Oct 6 07:52 sample.txt.gz
% gunzip sample.txt.gz (sample.txt.gz を伸長)
% ls -l (元通り)
-rw-r--r-- 1 user group 225280 Oct 6 07:52 sample.txt
また、
% gzip *.txt
と、複数のファイルを一度に圧縮することもできる。ただし、ファイルを一つにまとめるわけではないことに注意。UNIX でのアーカイブ (ファイルを一つにまとめること) には tar コマンドがよく使われる。
>> コマンド tar *

オプション
-c 圧縮・伸長の結果を標準出力に書き出す。ファイルへの書き込みは行なわない
-d 伸長する
-l 圧縮ファイルの内容・圧縮率を表示
-n ファイル名とタイムスタンプを保存する
-r ディレクトリを再帰的に扱う
-v バーボーズモード
-1 圧縮にかかる時間を短くする
-9 圧縮率の高い圧縮方法を使う

gunzip・gzip・gzcat ともファイルの実体は同じだが (ハードリンクされている)、どの名前で起動されたかによって伸長・圧縮・表示と動作を変える。どの名前で起動してもオプションを明示的に指定することで、全ての機能を実行できる。つまり
% gunzip sample.txt.gz
% gzcat sample.txt.gz
は、
% gzip -d sample.txt.gz
% gzip -dc sample.txt.gz
と同じである。

2GB 問題
Solaris・HP-UX・Linux などの gzip は 2GB 超のファイルに未対応であることが多い。

gzip 自体には「2GB」というファイルサイズの上限はない。また、最近の Solaris・HP-UX・Linux などの OS 自体は 2GB 超のファイルを問題なく扱える。ただし互換性からか、ソースをコンパイルすると、ファイルオフセット (off_t) が 32bit になってしまう環境が多い。このような環境でコンパイルしたバイナリは、gzip に限らず 2GB 超のファイルを生成できないし、既にある 2GB 超のファイルにアクセスすることはできない。

一般的には、コンパイル時に -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE というオプションを付けてコンパイルすればファイルオフセットが 64bit になることが多いようだ (Solaris2.6・Solari8・ HP-UX 11i・Linux で確認。AIX ではちょっと違うらしい)。

世の中で広く使われている gzip のバージョンは 1.2.4 であるが、ファイルオフセットが 32bit な環境で make すると、ファイルオフセットが 32bit な gzip が生成され、2GB 超のファイルを扱うことができない。SunSite や Linux 標準の gzip はこのように make されたものが多いので、2GB 超のファイルに未対応なことが多いのである。この場合、Makefile の CFLAGS に、上記のオプションを追加して再コンパイルすれば解決する。

gzip-1.3.3 の configure は少し賢くて、64bit ファイルポインタが使える場合は上記オプションを勝手に追加してコンパイルしてくれるため、2GB 問題は起こらないだろう。

ちなみに、ファイルオフセットが 32bit なのか 64bit なのかは以下のソースをコンパイルして実行すればわかる。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
main(){
printf("%d\n", sizeof(off_t));
}
出力結果が 4 ならば 32bit、8 ならば 64bit である。4 と表示された場合でも、上記オプションを付けてコンパイルすると、大抵の環境では 8 に変わるだろう (今どきの OS ならば)。

FreeBSD では (*BSD すべて?) ファイルオフセットは 64bit なので、2GB 問題は発生しない。少なくとも 2.2.7-RELEASE 以降は問題なし。Solaris や HP-UX でも、64bit モードでインストールした場合は、オプションなしでもファイルオフセットが 64bit となる。

なお、gzip-1.2.4 には元ファイルのサイズが 2GB 超のとき、gzip -l で表示されるファイルサイズがマイナス値になってしまうというバグがある (表示だけの問題)。

4GB 問題
こちらはあまり深刻な問題ではない。gzip-1.2.4 において、展開後のサイズが 4GB 超の圧縮済ファイルを zcat したときに、ファイル内容異常などのエラーが起こると実行が打ち切られてしまうとか、エラーメッセージがおかしくなる、といった内容である (試したわけではないので、違うかも)。

gzip.org にてパッチが公開されているので、それをあてればよい。gzip-1.3.3 では修正済。FreeBSD では 5.3-RELEASE で上記パッチが適用された。

gzip の開発体制
こんな細かなことまで説明したくはないのだが、正式版である gzip-1.2.4 は 1992 年頃にリリースされたもので、それ以降正式版がリリースされていない。つまり、昔の不具合をずっと引きずっているわけである。

gzip-1.3.3 は 2002年に公開されているが、まだベータ版である (2005年6月現在)。2GB の問題も、4GB の問題も、gzip-1.3 系を正式リリースすれば解決する。誰か gzip の開発を引き継いでやってください。
>> コマンド compress *   gzcat *   gzexe *   tar *   bzip2 *   gzrecover *

gzrecover 壊れた gzip ファイルをリカバリする (破損/復旧/復活/gzip Recovery Toolkit/gzrt)

gzrecover コマンドを使うと、壊れた gzip ファイルをリカバリすることができる。ツールの名称は「gzip Recovery Toolkit」であるが、コマンド名は「gzrecover」である。また、ツールの略称やソースファイル名などでは「gzrt」という表記が使用されている。

復旧方法
gzip や tar の z オプション使用時に
unexpected end of file

Premature end of gzip compressed data: Input/output error
というエラーメッセージが表示され、展開/伸張が途中で失敗してしまう場合、gzrecover コマンドを使って復旧を試みてみるとよいだろう。

破損したファイルが backup.txt.gz とすると、
% gzrecover backup.txt.gz
とすることで backup.txt.recovered というファイルが作成される。

tar+gzip の場合
もし tar ファイルを gzip で圧縮していた場合は、gzrecover で復旧した後、さらに tar で展開する必要がある。gzrecover は元ファイルのエラーを無視し、読める部分を拾い出したものであるため、tar ファイルとしては不完全である可能性がある。しかし、GNU tar コマンドはエラーを含むかもしれない tar ファイルをうまく扱うことができない。よって、この場合は tar コマンドではなく cpio コマンドを使用する。
% cpio -F backup.tar.recovered -i -v
とすることで、できる限りのファイルを拾い出すことができるだろう。
>> コマンド gzip *   tar *

halo 画面にサークルを描く

>> コマンド xscreensaver *

halt シャットダウン

詳しい説明は shutdown の項を参照
>> コマンド shutdown *   reboot *
>> 読み方 halt *

hd ファイルのダンプ (8進数/10進数/16進数表示)

>> Linux hd(4)  
ファイルの内容をダンプする。hexdump -C とまったく同じ。詳細は hexdump コマンドの項を参照。
>> コマンド hexdump *   od *   beav *

head ファイルの先頭部分を表示 (パイプ)

引数にファイル名のみ渡すと、先頭の 10行を表示する。
% head sample.txt
(sample.txt の先頭 10行が出力される)

-数字 というオプションで、表示する行数を指定することが可能。
% cat sample.txt
aaa
bbb
ccc
% cat sample.txt | head -2 (先頭の 2行が出力される)
aaa
bbb
-n count ファイルの先頭の count 行を表示
つまり
% head -5 sample.txt

% head -n 5 sample.txt
は同じである。
-c count ファイルの先頭の count バイトを表示
% cat sample.txt | head -c 2 (先頭の 2バイトが出力される)
aa

ファイルの先頭 n 行と末尾の m 行を削除、という場合は tail を使うとよい。
>> コマンド cut *   tail *

helix らせん模様を描く

>> コマンド xscreensaver *

hexcalc 2進、8進、10進、16進数の計算ができる電卓

>> コマンド bc *   calc *   dc *   xcalc *

hexdump ファイルダンプ (8進数/10進数/16進数表示)

-b 1バイトごとに8進数で表示
-c 1バイトことにキャラクタで表示
-d 2バイトごとに10進数で表示
-o 2バイトごとに8進数で表示
-C 1バイトごとに16進数でダンプした上で、右側に文字も表示
hexdump -C とまったく同様なことを行う hd コマンドも用意されている。
>> コマンド hd *
-s n ダンプを開始するオフセットを指定する
>> コマンド beav *   hd *   od *

history 過去にタイプしたコマンドを表示する。csh・tcsh内部コマンド。

数字を指定すると、現在からさかのぼってその数だけのヒストリを表示する。
>> Cシェル変数 savehist *

hopalong フラクタル画像を描く

>> コマンド xscreensaver *

host 

hostname ホスト名を表示

オプションなしで実行すると、ホスト名を表示する。
% hostname
foo.bar.baz.com
-s オプションを付けると、
% hostname -s
foo
となる。

一般ユーザはホスト名を表示することしかできないが、root だけは
# hostname ホスト名
とすることで、ホスト名を変更することができる。ただしリブートすると元に戻ってしまうので注意。
FreeBSD では /etc/rc.conf の中の
hostname = "ホスト名"
の部分を変更することで、ホスト名を設定できる。他の OS でもホスト名を変更する場合は、/etc/ の下の設定ファイルを修正することが多い。
>> 設定ファイル /etc/rc.conf *

hypercube 4次元物体を2次元で表示

iconv 文字コードを変換する (パイプ)

iconv はロケールの仕組みにのっとった正統派文字コード変換コマンドである。nkf や qkc は日本語専用のため、便利ではあるが正統派とはいえない。

iconv は変換元文字コードと変換後文字コードの両方を指定する。
% iconv -f EUC-JP -t Shift_JIS < infile.txt > outfile.txt
⇒ infile.txt の文字コードを EUC-JP とみなし、Shift_JIS に変換して outfile.txt に出力する。
FreeBSD など一部の iconv では、変換元か変換後のいずれかの文字コードを省略した場合、環境変数 LC_ALL や LANG などに設定されているロケールを使用するが、すべての iconv でそのような挙動をするとは限らない。

入力ファイルに無効な文字 (-f で指定した文字コードと矛盾するようなデータ) が含まれていた場合、iconv はエラーとして終了する。FreeBSD の iconv では -c オプションを指定することで、無効な文字を無視して無視して続行することができる。Linux はなぜか man に記載はないが、-c オプションを指定できる (man にはないが、iconv --help だと -c オプションが表示される)。その他の iconv では必ずエラーで終了してしまうようだ。

iconv で指定する文字コードは OS によってかなり異なる。例えば HP-UX では EUC-JP や euc-jp ではダメで、eucjp としなくてはいけない。使用可能な文字コード一覧を調べる方法は iconv の実装によって異なるため、以下の方法を試してみてほしい。
% iconv -l
⇒ 使用可能な文字コード一覧を表示 (FreeBSD の iconv で確認)
% iconv --list
⇒ 使用可能な文字コード一覧を表示 (GNU の iconv で確認)
% man iconv
⇒ 文字コード一覧表示機能がない場合はマニュアルを読むこと
>> コマンド nkf *   qkc *   euctosj *   coco *
>> 用語集 ロケール *

id ユーザの UID、GID、グループ名を表示

ユーザの UID、GID、所属しているグループ名を表示する。
% id
uid=1001(foo) gid=1001(foo) groups=1001(foo), 0(wheel), 5(operator)
この例では、ユーザ foo の UID は 1001、GID は 1001 であり、foo・wheel・operator の 3つのグループに属していることがわかる。
>> コマンド chgrp *   vipw *   whoami *
>> 設定ファイル /etc/passwd *   /etc/group *

identify 画像ファイルのフォーマット・サイズなど調べる (ImageMagick)

画像ファイルを指定すると、
% identify sample.gif
sample.gif 302x231+0+0 PseudoClass 16c 2122b GIF 1s
と、高さ、幅、色情報、サイズ、画像形式などが表示される。-verbose オプションを付けると、
% identify -verbose sample.gif
Image: sample.gif
type: palette
class: PseudoClass
colors: 16
0: ( 0, 0, 0) #000000 black
1: ( 24, 24, 73) #181849
2: ( 48, 52,113) #303471
3: ( 89, 93, 89) #595d59
4: ( 97,101, 97) #616561 ~gray39
5: ( 73, 73,134) #494986
6: ( 89, 93,150) #595d96
7: (113,113,174) #7171ae
8: (134,134,190) #8686be
9: (190,186,190) #bebabe ~gray74
10: (190,190,190) #bebebe gray
11: (158,154,207) #9e9acf
12: (174,174,223) #aeaedf
13: (255,255,255) #ffffff white
14: ( 0, 0, 0) #000000 black
15: ( 0, 0, 0) #000000 black
signature: 7ab4317a86fd9ece02dd224f74c35b95
matte: False
runlength packets: 1374 of 69762
geometry: 302x231
depth: 8
filesize: 2122b
interlace: None
page geometry: 302x231+0+0
format: GIF
compression: Runlength Encoded
comments:
xwdump
と、詳細な情報が表示される。

GIF や PNG ならば、高さと幅は file コマンドでも調べられる。
% file hoge.png
hoge.png: PNG image data, 300 x 300, 4-bit colormap, interlaced
>> コマンド convert *   display *   ImageMagick *   xv *   file *

idprio アイドルスケジューリングを使用する

もともとは HP-UX にあったコマンドで、他の
>> コマンド rtprio *   nice *   renice *   priocntl *

ifconfig ネットワークインタフェースの設定を行う

LAN を組むとき、ネットワークインタフェースの設定が必要になる。書式は
# ifconfig インタフェース名 IPアドレス ネットマスク
である。

まず、ネットワークカード (Ethernet カード) が1枚だけささっているなら、dmesg コマンドで
ネットワークカードのデバイス名を確認する。FreeBSD なら
% dmesg | grep ed1
ed1 <NE2000 PCI Ethernet (RealTek 8029)> rev 0 int a irq 10 on pci0:11:0
ed1: address 52:54:00:d9:68:28, type NE2000 (16 bit)
などとなっているはずである。仮に
  • デバイス名が ed1
  • そのインタフェースに割り振る IP アドレスが 127.0.10.1
  • ネットマスクは 255.255.255.0
だったとしたら、
# ifconfig ed1 127.0.10.1 netmask 255.255.255.0
とする。

うまく設定できたか確認するには、LAN 内の他のマシンに対して
% ping IPアドレス
とする。反応があれば成功である。次に
% ping ホスト名
として、
ping: cannot resolve XXX: Host name lookup failure
となった場合は、DNS か /etc/hosts か /etc/resolv.conf の設定がおかしい。

現在設定されているインタフェースについては、netstat コマンドで確認できる。

ネットワークインタフェースの設定は /etc/rc.conf に書いておくことで、ブート時に毎回自動的に設定される。
>> コマンド netstat *
>> 設定ファイル /etc/rc.conf *   /etc/hosts *   /etc/resolv.conf *

ImageMagick グラフィックユーティリティ

ImageMagick というのはパッケージ名で、display・convert・identify・import などの各プログラムで構成されている。それぞれ、画像表示、フォーマット変換、各種画像操作などが行える。
>> コマンド display *   convert *   identify *   import *   xv *   netpbm *

import ウィンドウの画像をダンプする

import を実行した後、マウスでダンプしたいウィンドウを選択すると、magick.ps というファイルに PostScript形式で画像が保存される。

-window ウィンドウID
ダンプするウィンドウIDを指定する。rootを指定するとルートウィンドウ (画面全体) をダンプする。
>> コマンド xwininfo *
-frame ウィンドウマネージャがつけるウィンドウ枠も保存する。
-monochrome 白黒画像で保存

% import -window 0x10000d window.jpg
⇒ ウィンドウ ID が 0x10000d のウィンドウを (JPEG 形式で) window.jpg に保存する。
>> コマンド xwd *   display *   ImageMagick *

imsmap フラクタル画像を描く

>> コマンド xscreensaver *

indent C のソースを整形する (パイプ)

C 言語のソースのインデント・括弧の付け方などを変更する。
% indent foo.c
foo.c を直接書き換える。foo.cはfoo.c.BAKというファイル名に置き換えられる。
% indent foo.c bar.c
foo.c を整形したものをbar.cに書き込む。foo.c は変化しない。

オプション:
-br ブラケットの付け方を
if (...){
...
}
という形にする
-i数字 インデントあたりのスペースの数。デフォルトは4。
-pcs 関数の `(' 前にスペースを入れる。 int foo (); となる。
-sc コメントを
/*
* ......
*/
という形式にする。
-nsc コメントを
/*
......
*/
という形式にする。
>> コマンド gcc *

inetd ポートを見張り、クライアントからのリクエストがあるとサーバプログラムを起動する。

一口でサーバといっても、ftp サーバ、rsh サーバ、rlogin サーバ、rcp サーバ、WWW サーバ、telnet サーバ、SMTP サーバ、finger サーバ、pop3 サーバなどいろいろある。これらのサーバプログラムを全て常駐させておくと、メモリは喰うし負荷はかかるしであまりいいことはない。

そこで inetd はクライアントからの要求を見張り、そのクライアントに対応する要求があった時点で初めてサーバプログラムを起動する。

普通、inetd はブート時に自動的に起動される。設定ファイルは /etc/inetd.conf。
>> 設定ファイル /etc/inetd.conf *   netstat *

info info ドキュメント閲覧ツール

主に GNU が配布するプログラムの多くは man ではなく info に詳細なマニュアルが記載されている。単に
% info
とすると以下のような emacs ライクな画面になり、マシン内にインストールされている全 info ファイルの一覧が表示される。
File: dir,      Node: Top       This is the top of the INFO tree

This (the Directory node) gives a menu of major topics.
Typing "q" exits, "?" lists all Info commands, "d" returns here,
"h" gives a primer for first-timers,
"mEmacs" visits the Emacs manual, etc.

In Emacs, you can click mouse button 2 on a menu item or cross reference to select it.

* Menu:

Programming & development tools.
* As: (as).                     The GNU assembler.
* Binutils: (binutils).         The GNU binary utilities.
* Bzip2: (bzip2).               A program and library for data compression.
* CVS: (cvs).          Concurrent Versions System
* Gas: (as).                    The GNU assembler.
(略)
-----Info: (dir)Top, 198 lines --Top----------------------------------------------
アスタリスク `*' が付いている行が別ノードへのリンクである (ノード ≒ ページ)。別ノードに移動するにはカーソルを狙いのリンクに合わせ、Enter キーを押す。

カーソル移動・検索・ウィンドウ分割などは emacs 互換であるが、編集機能などは実装されていない。emacs にこだわるなら、emacs 上で M-x info として info-mode を利用する手もある。ただし微妙に info コマンドと emacs の info-mode の操作方法は異なるようだ。
>> コマンド mule *

その他のキーバインドは、最低以下のものを知っておいてほしい。
  • SPACE ページを下にスクロールさせる。ページ末尾まで到達したら次のノードへ移動
  • n 次のノードへ移動 (next)
  • p 次のノードへ移動 (previous)
  • l 最後に閲覧していたノード (前ページ) へ移動 (last)
  • u 階層構造を位置段階上がる (up)
  • q info コマンドを終了する (quit)

なお、--vi-keys オプションを付けて info を起動することで、vi ライクなキーバインドとなる。

info に引数を与えることで、指定した info ファイルを直接閲覧することができる。
% info gcc
% info as
info ファイルが存在せず、man が存在する場合は、man の出力をそのまま info 上で表示する。
% info mount
⇒ mount.info が存在しないため、mount(8) の結果を表示する。

Texinfo と Info について
Texinfo というドキュメント作成ツールが存在する。Texinfo 形式のファイル (拡張子は .texi) を 1つだけ作成すれば、印刷用マニュアルとオンラインマニュアルに変換できる。この Texinfo ファイルは、makeinfo というコマンドで info ファイルに変換することができる (拡張子は .info)。この info ファイルを閲覧するプログラムが info コマンドである。info ファイルは info2html というツールで HTML 化することができる。

どうでもいいが、当ページ管理人が一番嫌いな UNIX コマンドが info である。有益な情報が info 内にあるのに、見づらいし、操作しづらいから。info2html の吐く HTML も嫌い。世の人々は info に満足しているのだろうか?
>> コマンド man *

init ログイン処理の初期化

UNIX で一番最初に実行されるプロセスが init である。全てのプロセスは init から fork/exec されて作成される。

init は最初に sh スクリプト /etc/rc を実行する。/etc/rc の中では
  • /etc/fstab を参照しながら /、/usr、/var などのファイルシステムをマウントする
  • /etc/rc.network や /etc/rc.serial を実行する
  • ホストの設定ファイル /etc/rc.conf を読み込み、その内容に従って sendmail などの<li>各種デーモン・/usr/local/etc/rc.d/*.sh を実行する。
が順に行われる。

init は最後に /etc/ttys を参照しつつ /usr/libexec/getty を実行する。FreeBSD でのデフォルトでは、getty が 3つ起動される。getty は
Login:
と表示し、ユーザ名が入力されるのを待つ。ユーザ名が実行されると、getty は login コマンドを実行する。例えば hoge というユーザ名が入力されると
/usr/bin/login -p hoge
を実行する。

login コマンドは
Password:
と表示し、パスワード入力を待つ。パスワードが入力されたら、得られたユーザ名とパスワードを照合し、/etc/master.passwd (実際はデータベース化された /etc/spwd.db) と照らし合わせて正しいパスワードかどうかを調べる。正しければそのユーザのログインシェルを実行するわけである。

ユーザがログアウトすると login コマンドが終了し、init に処理が戻る。すると、init は再度 getty を実行し、再びユーザがログインしてくるのを待つ。

/etc/ttys を変更することで、xdm や getty などの細かな設定を行うことができる。
>> 設定ファイル /etc/ttys *   /etc/passwd *

jcatman 日本語マニュアル対応の catman

FreeBSD では、日本語マニュアルを catman コマンドで整形すると日本語部分が化けてしまう。この場合は jcatman コマンドを使うとよい。
% jcatman /usr/local/man/ja_JP.EUC/man1
⇒ /usr/local/man/ja_JP.EUC/man1 以下のマニュアルを整形する。
詳しくは catman の項を参照。
>> コマンド catman *   man *   jman *

jlatex TeX コンパイラ

TeX のソースをエディタで作成し
% jlatex sample.tex
とすると sample.dvi ができる。
% xdvi sample.dvi
とすることで印刷時の仕上りを見ることができる。
>> コマンド xdvi *   dvi2ps *   dvi2tty *

jless 日本語を表示できる less

FreeBSD で日本語を表示するには less ではなく jless (ja-less) を使い、さらに環境変数 LANG や LESSCHARSET を
% setenv LANG ja (以下 csh・tcsh の場合)
% setenv LANG japanese
% setenv LESSCHARSET japanese
% setenv LESSCHARSET ja_JP.EUC
% export LANG=ja (以下 sh・bash の場合)
% export LANG=japanese
% export LESSCHARSET=ja
% export LESSCHARSET=japanese
などと設定する必要がある。FreeBSD なら
% setenv LESSCHARSET ja_JP.EUC
とするのがよいだろう。

jless 自体の説明は less の項で行う。
>> コマンド less *
>> 環境変数 LANG *

jman 日本語のオンラインマニュアルを表示

FreeBSD の場合、
% setenv LANG ja_JP.EUC
% setenv PAGER jless (日本語が通るページャを指定)
% setenv LESSCHARSET ja (jless で日本語が表示できるようにする)
として
% jman ls
とすると日本語マニュアルが表示される。環境変数 LANG を設定しないと、jman コマンドを実行しても英語マニュアルが表示されてしまう。PAGER と LESSCHARSET は、日本語を表示するための設定。

当ページ管理人は ~/.cshrc の中に
setenv PAGER jless
setenv LESSCHARSET
alias jman "env LANG=ja_JP.EUC jman"
と書いている。bash を使っているなら
export PAGER=jless
export LESSCHARSET=ja
alias jman="env LANG=ja_JP.EUC jman"
を ~/.profile に書いておくとよい。

jman コマンドが存在せず、環境変数 LANG によって日本語マニュアルを表示するかどうかを決める UNIX もある (例えば Solaris)。その場合、
% alias jman "env LANG=ja man" (csh・tcsh の場合)
% alias jman="env LANG=ja man" (sh・bash の場合)
とすることで、man で英語マニュアル、jman で日本語マニュアルというふうに使い分けることができる。

オンラインマニュアル自体の説明は man の項を参照。
>> コマンド man *   less *   jless *
>> 環境変数 LANG *   PAGER *

jnethack ローグ風のゲーム(日本語版)

テキスト表示のダンジョン探検ゲーム

jobs 実行中のジョブを表示

「ジョブ」とは、プロセスと似た概念で、現在実行中のプログラムのことを指す。ジョブとプロセスの違いは、
% ls | more
のようなパイプを使った場合に現れる。ls と more はそれぞれ別のプロセスだが、ls | more はひとつのジョブである。上記の場合、ls を実行したまま more を止める、というような操作は (操作している人にとっては) あまり意味がない。操作している人の立場から見て、複数のプロセスをグループ化したものがジョブである。

現在実行中のジョブ一覧を見る場合は jobs を使う。
% more sample.dat
^Z
⇒ Ctrl-z で more を中断
% jobs
[1] + Suspended more sample.dat
ここで行頭の [1] はジョブ番号、+ の印が付いているのはカレントジョブで、
引数なしで fg や bg を実行するとカレントジョブが対象となる。さらにコマンドを実行してみよう。
% emacs test.c
^Z
⇒ emacs を中断
% jobs
[1] - Suspended more sample.dat
[2] + Suspended mule test.c

% kill %2
[2] Terminated emacs test.c
% fg %1
⇒ more の処理に戻る

>> コマンド fg *   bg *   kill *

jot 連番・ランダムデータを生成

1〜5 までの連続した数字列を生成するには
% jot 5
1
2
3
4
5
とする。開始番号を指定するには引数を 2つ指定し、
% jot 5 20 (20〜24 の数字を出力)
とする。終了番号を指定するには、さらにもう 1つ引数を追加して、
% jot 5 20 100
20
40
60
80
100
とする。

-r ランダムな 1〜100 の数字列を生成する
% jot -r 500
⇒ 1〜100 のランダムな数字を 500 個表示する。
% jot -r 500 30
⇒ 30〜100 のランダムな数字を 500 個表示する。
% jot -r 500 30 50
⇒ 30〜50 のランダムな数字を 500 個表示する。
ランダムな「文字列」ではなく、ランダムなバイナリデータを生成したい場合は、openssl rand を使うとよい。
>> コマンド openssl *
-w 書式文字列
printf(3) で指定できる書式文字列を与えることで、生成するデータの書式を指定できる。
% jot -w %03d 5
001
002
003
004
005
% touch `jot -w file%03d.txt 999`
⇒ file001.txt〜file999.txt を作成する。

kakasi 漢字をひらがな・カタカナ・ローマ字に変換

% echo '漢字を平仮名に' | kakasi -JH
かんじをひらがなに
% echo '漢字をカタカナに' | kakasi -JK
カンジをカタカナに
% echo '全てをローマ字に' | kakasi -Ha -Ka -Ja -Ea -ka
subetewohiraganani

kbdcontrol キーボードの種類を決める

コンソールでのキーボードのタイプを決める。普通は /etc/rc.conf に書いた定義を元に、ブート時に /etc/rc.local でキーボードタイプがセットされる。手動で設定したい場合は
% kbdcontrol -l /usr/share/sysconf/keymaps/jp.106x
などとする (一般ユーザでも実行できる)。

この設定は、X Window System 上には反映されない。X のキーボードマップを設定するには、XF86Setup コマンドを使うか、直接 /etc/XF86Config を書き換えること。
>> 設定ファイル /etc/rc.conf *   /usr/share/sysconf/keymaps/* *
>> コマンド XF86Setup *

kcon キーボードのコントロールとマッピング

kon コンソールで日本語を表示する

普通は X window system 上でないと日本語を表示することはできないが、kon を使うと X window system がなくても日本語を表示することができる。

kill プロセス・ジョブを殺す

プログラムの挙動がおかしくなって入力を受け付けなくなり、C-c でも終了しなくなった場合、kill でシグナルを送って停止させることができる。

まず ps コマンドを実行し、
% ps axww | grep hoge (BSD 系の場合)
% ps -ef | grep hoge (SystemV 系の場合)
終了させたいプロセスのプロセス番号を確認する。プロセス番号を確認したら
% kill プロセス番号
を実行する。もういちど ps コマンドで確認して、まだプロセスが生きていたら、
% kill -9 プロセス番号
とすると確実に終了させることができる。

-l シグナルの一覧を表示
% kill -l (以下は FreeBSD の場合。シグナルの種類は OS によって結構違う)
HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM
URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH
INFO USR1 USR2
主要シグナルの説明
  • INT 中断(インタラプト)。コマンドラインで C-c すると送られるシグナル。
  • TERM プロセスを終了させる。シグナル名を指定しないと TERM が送られる。
  • STOP プロセスを中断させる。CONT で再開できる。C-z のサスペンドと同じ。
  • HUP 回線切断。デーモンプロセス (apache や inetd など)を再起動させる場合によく使われる。
  • CONT STOPで中断したプロセスを再開させる。
  • KILL プロセスを強制終了させる。
シグナルはシグナル名で指定してもよいし、シグナルの番号でもよい。例えば HUP シグナルは 1番 (kill -l で 1番目に表示されるから) なので、
% kill -HUP プロセス番号
% kill -1 プロセス番号
は、どちらも同じである。また、kill -KILL と kill -9 も同じである。なお、シグナル名 (やシグナル番号) を省略したときは SIGTERM シグナルが使われるので、
% kill プロセス番号
% kill -TERM プロセス番号
は、同じ意味である。

プログラムの書き方次第で、プロセスがシグナルを受けても、それを無視させることができる。例えば HUP シグナルをブロックしていれば、C-c で終了しないようにできる。しかしブロックできないシグナルが一つだけある。それは KILL シグナル (-9) で、このシグナルを受けると、あらゆるプロセスは OS によって強制的に終了させられる。
>> コマンド fg *   bg *   killall *   ps *   suspend *   xkill *

killall コマンド名を指定して kill

以下は、BSD・Linux の killall の説明である。

オプション:
-l シグナル一覧を表示
-m コマンド名を正規表現で指定する
-s シグナルを送るプロセスを表示する。実際にはシグナルは送らない。

まず kterm をバックグラウンドで実行する。
% kterm &
[1] 4985
kterm を kill したくなったが、ps でプロセス ID を調べるのが面倒である。そこで killall を使う。まずは -s オプションを付けて、どのプロセスにシグナルが送られるか確認する。
% killall -s kterm
kill -TERM 4985
今度は本当に kterm を kill する。
% killall kterm

inetd を再起動する場合は以下のようにする。
# killall -HUP inetd

もし指定のコマンドに該当するものが複数個ある場合は、全てのプロセスにシグナルを送る。だから上の例を X 上の kterm から実行すると、全ての kterm が終了してしまう。

killall のオプションを複数指定するときは
% killall -ms
などとせずに
% killall -m -s
としなくてはならない。

Solaris の killall は、全プロセスを終了させるコマンドである。これは root 権限がないと実行できない。
% su
# killall
とするだけで、daemon を含むほとんどのプロセスが終了してしまうので、BSD・Linux の killall に慣れている人は注意した方がよいだろう。
>> コマンド kill *

kinput2 日本語を入力するためのツール。

kterm ターミナルエミュレータ。xterm の日本語対応版

普通はこの上でシェル (tcsh や bash など) を実行し、いろいろなコマンドを実行する。要は、kterm は画面上に文字列を表示するためのプログラムである。これを端末エミュレータと言う。

Ctrl キーを押しながら、マウスの各ボタンを押すことでメニューが出てくる。知らないと困るのが、「Ctrl+マウスの真ん中ボタン」で表示される「VT Options」の中の「Do Full Reset」。バイナリファイルを表示すると (例えば誤って cat /bin/ls を実行した場合)、画面が化けたままになってしまうことがある。こういうときに「Do Full Reset」を行うことで、回復することができる。

-T str ウィンドウのタイトルを指定する。省略すると「kterm」となる。
-fn fontname フォント名
-fb fontname 太字 (bold) のフォント名
-fk fontname 漢字フォント名
-fkb fontname 太字 (bold) の漢字フォント名
-fr fontname JIS X 0201 のフォント。
JIS X 0201 はASCII コードと似ているが微妙に違う。よくわからない場合は -fn と同じフォントを指定すること。指定可能なフォントは xlsfonts などで調べることができる。
>> コマンド xlsfonts *
-km kanjimode
漢字コードを指定する。kterm は JIS コード (ISO-2022-JP) はいつでも出力できるが、EUC と SJIS の自動判別は難しいため、EUC と SJIS のどちらを表示できるようにするかはユーザが選ばなくてはいけない。
% kterm -km euc
とすると、JIS と EUC を表示できる。一方
% kterm -km sjis
だと、JIS と SJIS が表示できる。この漢字モードは kterm 上で
「Ctrl+マウスの真ん中ボタン」
で開くメニューの中で、「Japanese EUC Mode」「Shift-JIS Mode」を選択することで kterm 実行中に変更することができる。

UNIX 上では EUC を使うことの方が多いので、普通は EUC モードにしておくとよいだろう。ただしその場合は SJIS のファイルを cat コマンドなどで表示すると化けてしまうので、
% cat sjis-flie | nkf -e
とするか、cat を使わず mule や less コマンドでファイルを見るとよい。
>> コマンド nkf *
-C コンソールのメッセージを表示する (/dev/console 宛に出力された文字も出力されるようになる)
>> コマンド xconsole *
-cr colorname カーソル部分の色を指定する。
-hc colorname マウスでドラッグした部分の色を指定する。
このオプションは xterm のみ使用可で、kterm では使えないらしい。色の名前は showrgb・xcolors などで調べることができる。
>> コマンド showrgb *   xcolors *
-b 数字 kterm 内部の端から、ウィンドウ自体の端までのドット数。
-e コマンド
kterm を実行すると、そのウィンドウの中で指定したプログラムを実行する。
% kterm -e top
などと指定する。そのプログラムが終了すると自動的に kterm も閉じてしまうので、
% kterm -e cal
は、cal の実行が終ると一瞬で kterm も閉じてしまう。そういうときは、
% kterm -e sh -c 'cal; exec sh' (シェルが起動する)
% kterm -e sh -c 'cal; read line' (Enter キーを押すと終了)
とすればよい。

また、-e オプションは
% kterm -cr red -e top
のように最後に指定すること。
% kterm -e top -cr red
ではうまくいかない。
-mc 数字 マウスクリックの際に、ダブル/トリプルクリックと認識される最大時間を指定する。
% kterm -mc 300
とすると、300ミリ秒 (0.3秒) を越えると、ダブルクリックとは認識されない。
-sb スクロールバーを表示する
スクロールバーを操作することで、画面からスクロールしてしまった部分を参照することができる。スクロールバーが表示されていない場合は、「Ctrl+マウスの真ん中ボタン」を押して一番上の「Enable Scrollbar」を選択すると、スクロールバーが表示される。-sb オプションを付けると、最初からスクロールバーが表示される。

また、スクロールバーを操作しなくても、Shift+PageUp・Shift+PageDown で kterm の画面を遡ることができる。
-sl 数字 スクロールバーで戻ることができる行数を指定する。
たまに、もっと戻りたいのだが、これ以上戻れないという状況がある。最近のマシンは潤沢なメモリを積んでいるので、1000 行程度指定しておいた方がよいだろう。デフォルトは 64 行。
-r 文字色と背景色を逆にする

以下はリソース設定。~/.Xdefaults や ~/.Xresources に記述すること。
>> 設定ファイル ~/.Xdefaults *   ~/.Xresources *
charClass
kterm の文字上でダブルクリックした場合、一定範囲の文字列がカットバッファに入る(反転表示される)。charClass を設定することで、どこまでを文字列として認識するかを設定できる。お勧めは
KTerm*VT100*charClass: 35:48,37-38:48,43:48,45-47:48,58:48,61:48,63-64:48,126:48
これだと、URL らしき文字列の上でダブルクリックすることで、カットバッファに格納できる。
EightBitInput
kterm + mule -nw 上で、Alt-v で上方向に1画面スクロールせず、わざわざ ESC-v とタイプしている人はこれを false にするとよい。Alt-v が Esc-v と同等に扱われる。ただし、kterm + emacs-20.7 -nw ではこれがなくても Alt-v が使える模様。なぜ?

お勧めオプションは、
% kterm -fn 8x16 -fr 8x16 -fk kanji16 -km euc -sl 1000
である。フォントは16ドット。漢字モードは EUC。スクロールバーで戻れる行数は 1000 行。オプションでなくリソース設定で行うなら、~/.Xdefaults や ~/.Xresources に
*VT100*font: 8x16
*VT100*romanKanaFont: 8x16
*VT100*kanjiFont: kanji16
*VT100*kanjiMode: euc
*VT100*saveLines: 1000
*VT100*charClass: 35:48,37-38:48,43:48,45-47:48,58:48,61:48,63-64:48,126:48
*VT100*EightBitInput: false
と書いておくとよい。
>> 設定ファイル ~/.Xdefaults *   ~/.Xresources *

>> コマンド xterm *   Eterm *

last 過去のブート、シャットダウン、ログインの記録を表示

% last user
⇒ ユーザ名 user のログイン情報を表示

lastcomm これまで実行されたコマンドの一覧を表示

過去に実行されたコマンドを表示する。
% lastcomm
jman             -       user   ttyp3      0.00 secs Sun Oct 10 10:30 
sh               -       user   ttyp3      0.00 secs Sun Oct 10 10:30 
jless            -       user   ttyp3      0.02 secs Sun Oct 10 10:30 
ping             -       user   ttyv0      0.00 secs Sun Oct 10 10:30 
sleep            -       user   ttyv0      0.00 secs Sun Oct 10 10:30 
mule-19.28       -       user   ttyp1      1.41 secs Sun Oct 10 10:25 
gzcat            -       user   ttyp3      0.00 secs Sun Oct 10 10:30 
jless            -       user   ttyp3      0.02 secs Sun Oct 10 10:30 
ls               -       user   ttyp3      0.00 secs Sun Oct 10 10:30 
ping             -       user   ttyv0      0.00 secs Sun Oct 10 10:29 
jless            -       user   ttyp3      0.14 secs Sun Oct 10 10:29 
cron             -F      root   __         0.00 secs Sun Oct 10 10:30 
sh               -S      root   __         0.00 secs Sun Oct 10 10:30 
atrun            -S      root   __         0.00 secs Sun Oct 10 10:30 
ls               -       user   ttyp3      0.00 secs Sun Oct 10 10:29 
lastcomm は /var/account/acct を読みこむので、事前に accton でシステムのログを作成しておく必要がある。
>> コマンド ac *   accton *   sa *

ld リンカ。リンクエディタ

>> コマンド ldd *   gcc *

ldconfig 共有ライブラリを検索するパスを設定

ldd で説明したダイナミックリンクは、ライブラリがどのディレクトリに置いてあるかという情報が必要になる。一般的には /usr/lib、/usr/X11R6/lib、/usr/local/libなどに共有ライブラリが置かれている。
>> コマンド ldd *

ldd ダイナミックリンクの関係を表示

プログラムを作成する場合、既に用意してあるライブラリを利用することが多い。例えばほとんどのプログラムでは printf(3) を使うが、だからといってほとんどのバイナリに printf(3) のコードを埋め込むのはディスクスペースの無駄である。そこでコンパイル時にライブラリをリンクするのではなく、実行時に動的にリンクを行う仕組みがある。ldd はコマンドがどのランタイムライブラリを参照しているか表示する。
% ldd /usr/X11R6/bin/kterm
/usr/X11R6/bin/kterm:
-lXt.6 => /usr/X11R6/lib/libXt.so.6.0 (0x806f000)
-lX11.6 => /usr/X11R6/lib/libX11.so.6.1 (0x80bd000)
-lXmu.6 => /usr/X11R6/lib/libXmu.so.6.0 (0x805f000)
-lSM.6 => /usr/X11R6/lib/libSM.so.6.0 (0x8153000)
-lICE.6 => /usr/X11R6/lib/libICE.so.6.0 (0x815b000)
-lgnumalloc.2 => /usr/lib/libgnumalloc.so.2.0 (0x816d000)
-ltermcap.2 => /usr/lib/libtermcap.so.2.1 (0x8171000)
-lc.2 => /usr/lib/libc.so.2.2 (0x8175000)

ダイナミックリンクは、バイナリのサイズが少なくなることとひきかえに、そのバイナリ単独での実行が不可能になるという欠点がある。

この例では kterm は8つのランタイムライブラリを実行時に必要とし、1つでも欠けると実行することはできない。もし OS の起動時に何か不具合があってシングルユーザモードで起動したとき、/bin/ls や /bin/mount が/usr/lib/libc.* を必要としたとしたら、/usr がマウントされていないと復旧作業はできなくなってしまう。そのため、/bin、/sbin などのコマンドはランタイムライブラリを必要としないように作られている。

kterm のようなリンク方式を、ダイナミックリンク・動的リンクと言い、ls のようなリンク方式をスタティックリンク・静的リンクという。静的にリンクされたバイナリを ldd で見ると
% ldd /bin/ls
ldd: /bin/ls: not a dynamic executable
となる。
>> コマンド ar *   ld *   ldconfig *
>> 環境変数 LD_LIBRARY_PATH *

leave ログアウトする予定の時間を知らせる

% leave 1630
午後4時30分にログアウトする予定。5分前にアラームとメッセージが表示され、4時30分にもアラームとメッセージで時間になったことを知らせる。その後1分おきにアラームとメッセージを表示する。
% leave +30
今から30分後にログアウトする予定

less ファイル表示プログラム (ページャ)

あるコマンドを実行結果や、ファイルの内容を見たいとき、1画面に収まりきらずスクロールしてしまって最初の部分が見えないことがある。そういう場合、
% ls -l | less

% less file.txt
などとすることでゆっくり見ることができる。

more ではできなかったバックスクロールに対応、他にも gzip や compress で圧縮されたファイル (*.gz や *.Z) を直接見ることができるなど、いろいろな機能が付け加えられている。なお、FreeBSD の less は日本語を表示できないので、jless (ja-less) を使うこと。
>> コマンド jless *

最初に使うときは
  • q で終了 (more と違って、less はファイルの最後に到達しても終了しない)
  • カーソルキー・Ctrl-p・Ctrl-n で上下スクロール
  • <・>で先頭行・最終行に移動
  • / で検索 (正規表現として扱われる)
ということを覚えておくとよい。

キーバインド。less は1つの動作に対して複数のキーが割り当てられている。例えば less を終了するには q か :q か :Q か ZZ のうちいずれを使ってもよい。
q :q :Q ZZ less を終了
カーソルキー 前後に1行移動。なお、左右スクロールもできる。
数字 指定行に移動
f SPACE ^V ^F 1画面前進
b ^B ESC-v 1画面後退
RETURN e j ^N ^E ^J 1行前進
y k ^Y ^P ^K 1行後退
d ^D 1/2画面前進
u ^U 1/2画面後退
r ^R ^L 画面を再表示
R ファイルを読み直して再表示
g < ESC-< 先頭行に移動
G > ESC-> 最終行に移動
/[!*@]文字列 文字列を前方検索(正規表現として扱われる)
/!文字列 文字列を含まない行を検索
/*文字列 コマンドラインで指定した全てのファイルを検索
/@文字列 ファイルの先頭から検索
?[!*@]文字列 文字列を後方検索。/と同じ機能を持つ
n 次検索。一度 / で検索した後、もう一度同じ文字列を検索したいとき n を使う。
N nとは逆方向に次検索
ESC-u 検索にマッチした部分の反転表示を解除
v エディタを起動して現在表示しているファイル編集
>> 環境変数 EDITOR *
= ^G :f 現在位置の行数、バイト数、パーセンテージを表示
h 簡易ヘルプを表示
V バージョンを表示
!(リターン) シェルを起動
!コマンド コマンドを実行
!! 直前の!コマンドを再実行

オプションは以下の通り。

-e ファイル終端に2度到達すると終了する
-E ファイル終端に1度到達すると終了する (more と同じ動作)
-f ディレクトリや実行ファイルも表示する。less でバイナリファイルを見ようとすると「"/bin/ls" may be a binary file. See it anyway?」などという確認メッセージが表示され、`y' を押すと内容を見ることができる。-f オプションを付けると、バイナリファイルでも確認を求めずに表示する。
-g サーチにマッチした文字列のうち最後にマッチしたものだけを反転表示する
-G サーチにマッチした文字列を反転表示しない
-jn(数字) ターゲットラインの位置を指定する。ターゲットラインとは、サーチにマッチした文字列が表示される行のこと。-j10 とすると、サーチにマッチした文字列は上から 10行目に表示される。 -j-10 とすると、下から 10行目に表示される。
-kファイル名 lesskey で作られたキーバインド設定ファイルを読み込む
-m プロンプトに常に現在行のパーセンテージを表示する
-M プロンプトに常に現在行のパーセンテージと行数を表示する
-n 行数計算をしない。非常にサイズの大きいファイルの場合動作が高速化される
-N 各行の先頭に行番号を表示する
-oファイル名 入力をファイルにコピーする。パイプから入力した場合に有用
-Oファイル名 -oと同じだが、同名のファイルがすでに存在したら上書きする
-pパターン 起動後、指定されたパターンをサーチする
-q エラーの際にあまりビープ音を鳴らさない (状況による)
-Q エラーの際にビープ音を鳴らさない
-r コントロールコードをそのまま表示する。デフォルトでは control-A は ^A と表示されるが、-r を指定するとそのまま表示する。これによって、cat で日本語が表示できる環境なら、less -r で日本語が表示できるかも。
-S 1行の文字数が画面の横幅を超えた場合、折り返さず、はみでた部分は表示しない
-V バージョンを表示
-w 空行を表す記号に~を表示しない
-xn(数字) タブ幅をnに設定する。デフォルトは 8
-zn(数字) f キー、b キーを押した時にスクロールする行数を指定する。n がマイナスなら (スクリーンの縦幅-n) 行スクロールする

お勧めオプションは -gj10。環境変数 LESS にオプションを設定することで、デフォルトオプションとして扱われる。例えば
% setenv LESS -gj10 (csh・tcsh の場合)
% export LESS=-gj10 (sh・bash の場合)
などと設定する。

なお、less を使わなくても kterm なら Shift+PageUp、Shift+PageDown でさかのぼることもできるので、覚えておくとよいだろう。
>> コマンド jless *   more *   xless *   kterm *
>> 環境変数 PAGER *

lesskey less のキーバインドを変更

lex 字句解析パーサ生成プログラム

lex は「『字句解析を行うプログラムのソース』を生成するプログラム」である。入力された文字列が数値かアルファベットかを判定するプログラムを作って簡単な例を示そう。
%{
#include <stdio.h>
%}

%%
[\t ]+ { /* 何もしない */ }
[0-9]+ { printf("digit=%s",yytext); }
[a-z]+ { printf("alphabet=%s",yytext); }
\n { /* 何もしない */ }
. { printf("Syntax error\n"); }
%%
という内容の sample.l というファイルを作成する。そして、
% lex sample.l
とすると、lex.yy.c というファイルが作成される。つまり、lex は「C のソース生成器」なわけだ。次に、このソースを
% cc lex.yy.c -ll
でコンパイルする。-ll は libl.a という lex 用のライブラリをリンクするためのオプションである。コンパイルできたら実行してみよう。
% ./a.out
123 (と入力)
digit=123
abc (と入力)
alphabet=abc
! (と入力)
Syntax error
123 456 abc (と入力)
digit=123
digit=456
alphabet=abc
a1b2 (と入力)
alphabet=a
digit=1
alphabet=b
digit=2
なんとなくそれなりに処理されている気がする。さて、sample.l をもう一度見てみよう。このファイルは
%{
定義部
%}
%%
規則部
%%
という構造になっている。定義部には規則部で使う変数・構造体の宣言や、#define・#include など、マクロやインクルードファイル関連を記述する。

一方、規則部には、
正規表現 { C のコード }
を並べておく。正規表現がマッチしたときに、対応する {} 内の部分が実行される。マッチした文字列は yytext という変数に代入される。

sample.l の規則部は、
  • スペースやタブなら何もしない
  • 0〜9 が連続する文字列なら、digit=… と表示
  • a〜z が連続する文字列なら、alphabet=… と表示
  • 改行コード (\n) なら何もしない。
  • それ以外の文字は Syntax error を表示
という意味である。

この例のように lex 単体で使ってもよいが、yacc と組み合わせて使うと簡単なインタプリタくらいなら手軽に作ることができる。
>> コマンド flex *   yacc *   bison *
>> 読み方 lex *

lha LHA・LZH ファイルの管理ツール

l アーカイブされているファイルの一覧を表示
x アーカイブされているファイルを展開
>> コマンド tar *

limit プロセスへの各種の制限を設定する。csh・tcsh の内部コマンド。

limit で設定できる制限値には、一般ユーザが変更できる(普通の)リミットと、root しか変更できないハードリミットがある。引数なしで limit を実行すると
% limit 
cputime         unlimited
filesize        unlimited
datasize        16384 kbytes
stacksize       8192 kbytes
coredumpsize    unlimited
memoryuse       30720 kbytes
descriptors     64 
memorylocked    10240 kbytes
maxproc         64 
と現在のリミット値が表示される。一方、-h オプションをつけると
% limit -h
cputime         unlimited
filesize        unlimited
datasize        131072 kbytes
stacksize       65536 kbytes
coredumpsize    unlimited
memoryuse       unlimited
descriptors     360 
memorylocked    124084 kbytes
maxproc         179 
とハードリミットが表示される。この状態では、最大プロセス数は64 (maxproc=64だから) だが、
% limit maxproc 179
とすることで、最大プロセス数を 179 にすることができる。しかし一般ユーザは
% limit maxproc 180
などとハードリミットを越える値をセットすることはできない。ハードリミットを変更することができるのは root のみである。

limit の各項目の意味以下の通り。
cputime
各プロセスが CPU を使うことのできる時間の上限
filesize
1つのファイルの長さの上限
datasize
sbrk(2) を用いてプログラムのテキスト領域の末尾を超えて増加させることのできる data+stack 領域のサイズの上限
stacksize
自動的に拡張されるスタックのサイズの上限
coredumpsize
コアダンプした際に作られるコアファイルのサイズの上限
% limit coredumpsize 0
で、コアダンプ時に core ファイルを生成しないようにすることができる。
memoryuse
各プロセスが使用できるメモリ使用量
descriptors
1ユーザが同時にオープン可能なファイル数の上限
memorylocked
???
maxproc
1ユーザが同時に実行可能なプロセス数の上限

値の単位は各項目ごとに異なる。cputime は
% limit cputime 1 1秒
% limit cputime 1m 1分
% limit cputime 1h 1時間
% limit cputime 1:1 1分1秒
で、maxproc・descriptors はそれぞれプロセス、デスクリプタの個数、その他は
% limit filesize 1 1キロバイト
% limit filesize 1m 1メガバイト
などと指定する。
>> コマンド unlimit *   ulimit *
>> 用語集 プロセス *

lint Cプログラムの文法チェッカ

>> コマンド gcc *

listres ウィジェットリソースのリストを表示

はっきり言って、何のためのコマンドなのかわかりまへん。
>> コマンド appres *

ln ハードリンク・シンボリックリンクを張る。

「リンクを張る」とはファイル・ディレクトリの別名を作るようなもので、ファイル・ディレクトリを別の名前で参照することができる。リンクにはハードリンクとシンボリックリンクがあり、それぞれの利点があるが、一般的にはシンボリックリンクを使う方がよいだろう。

ハードリンクを作ることで、あるファイルの複製を作ることができるが、一度ハードリンクを作ってしまうと、参照先 (実体) や参照元などという区別はなくなってしまう。
% ln file-a file-b
とすることで、file-a と同じ内容を持つ file-b というファイルを作成することができる。これをハードリンクと言う。このとき file-a は実際に存在していなくてはならず、新たに作成される file-b が既に存在していてはいけない。一度ハードリンクを張ってしまうと、本当のファイル/別名のファイルという区別はなくなる。これは、file-a と file-b が同じ i-node を指すようになっているからである。

ハードリンクと i-node の関係について ls -li で確かめてみよう。ls に -i オプションを付けることで i-node の情報を表示することができる。
% ls -li file-a
414820 -rw-r--r-- 1 user group 10 Aug 4 14:49 file-a
現在は file-a が存在し、i-node は 414820 である。なお、i-node とは、ファイル・ディレクトリに付けられた一意な番号である。ファイル・ディレクトリ識別番号とでも考えればいいだろう。

file-a のハードリンク file-b を作成する。
% ln file-a file-b
もう一度 ls -li を実行してみよう。
% ls -li file-a file-b
414820 -rw-r--r-- 2 user group 10 Aug 4 14:49 file-a
414820 -rw-r--r-- 2 user group 10 Aug 4 14:49 file-b
file-a と file-b の i-node が同じなのに注目してほしい。i-node が同じということは、file-a と file-b は全く違いがないということである。file-a の内容を書き換えようとすると、OS は file-a の i-node が 414820 であることを調べ、ディスク中の 414820 に対応するファイルが書き換えられる。次に file-b を中身を表示しようとした場合も、OS が file-b の i-node が 414820 であることを調べ、ディスク中の 414820 に対応するファイルの中身を表示する。つまり、file-a を書き換えても file-b を書き換えても、同じディスクの領域を書き換えることになる。同様に、パーミッション、ファイルオーナーも共有される。file-a のパーミッションを変更すると file-b にも反映される。

では、削除時のことを考えてみよう。単純に削除してしまうと、file-a を削除したとき i-node 414820 に対応する領域がなくなり、file-b は残っているもののファイル自体は削除され、参照できなくなってしまう。それを避けるため、UNIX のファイルシステムはリンク数という情報を保持している。先程の ls -li の表示で、パーミッションの後の数字がそれである。file-a しか存在しないときはリンク数は 1 であるが、file-b を作成するとリンク数が 2 に増えていることに注意してほしい。file-a を削除するとき、OS はリンク数を 1 減らす。リンク数が 0 にならないとファイルの実体は削除しない。
% ls -li file-a file-b (それぞれのリンク数は2)
414820 -rw-r--r-- 2 user group 10 Aug 4 14:49 file-a
414820 -rw-r--r-- 2 user group 10 Aug 4 14:49 file-b
% rm file-a (file-aを削除)
% ls -li file-b (リンク数が1になった)
414820 -rw-r--r-- 1 user group 10 Aug 4 14:49 file-b
上の例では、rm file-a でリンク数を1減らしてもリンク数が 0 にはならないので、i-node 414820 に対応するディスク領域は削除されないわけである。この状態で rm file-b を実行すると、リンク数は 0 になり、i-node 414820 に対応するディスク領域は消去される。

なお、一般的にディレクトリのハードリンクは作成できない。これは、循環ディレクトリができないようにするためである。例えば /hoge がディレクトリの場合、
% ln /hoge /hoge/dir
を実行すると、/hoge/dir/dir/dir/dir/dir/dir/.... という無限のディレクトリができることになる (/hoge/dir は /hoge と同じだから)。そのため、ディレクトリのハードリンクは作成できないことになっている。ただし、Solaris などでは root のみがディレクトリのハードリンクを作成できる(ln コマンドでは不可能。システムコール link(2) を使う必要がある)。しかし、一般的にはシンボリックリンクを使う方がよいだろう。

ファイルシステム (df コマンドで表示されるもの) をまたいだハードリンクを作成できないことに注意。これは、ハードリンクは異なるファイルが同じ i-node を指すことで実現されているが、ファイルシステムが異なると、全く違う i-node が付けられるからである。つまり/dev/sd0 の i-node 100 が /usr/hoge だったとしても、/dev/wd0 の i-node 100 は/var/hoge かもしれない。/dev/wd0 の中のファイルと /dev/sd0 の中のファイルとでは、同じ i-node を共有することができないのである。

次に、シンボリックリンクについて説明する。ln にオプションを付けるとシンボリックリンクが作成される。
% ln -s file-a file-b
とすることで、file-a の別名である file-b ができる。シンボリックリンクはハードリンクとは違い、参照先(実体)と参照元という区別がはっきりと存在する。これは ls -l で見るとわかりやすいだろう。
% ls -l file-a file-b
-rw-r--r-- 1 user group 0 Aug 1 16:14 file-a
lrwxrwxrwx 1 user group 3 Aug 1 16:14 file-b -> file-a
先頭のファイルタイプが「l」であることから、file-b は通常ファイルではなくシンボリックリンクであり、file-a を指していることがわかる。

シンボリックリンクは、参照先が存在しなくてもエラーとならない。つまり、file-a が存在しなくても
% ln -s file-a file-b
とすることができる。また、シンボリックリンクはハードリンクとは違って、別のファイルシステムへもリンクを張ることができる。

なお、
% cd /tmp; ln -s /home/foo/bar/sample

% ln -s /home/foo/bar/sample /tmp/sample
と同じである。つまり、他のディレクトリ中のファイルへのシンボリックリンクをカレントディレクトリに作成したかったら、
% ln -s /home/foo/bar/sample
と、シンボリックリンク名を省略できる。シンボリックリンクの削除をしたいときは、普通に rm コマンドを使えばよい。rm はシンボリックリンクの指す先ではなく、リンク自体を削除する。
>> コマンド rm *

シンボリックリンクのパーミッション
シンボリックリンク自体のパーミッションは全く意味を持たない。
lrwxrwxrwx 1 user group 3 Aug 1 16:14 file-b -> file-a
でも
l--------- 1 user group 3 Aug 1 16:14 file-b -> file-a
でも全く違いはない。有効なのはリンク先の file-a のパーミッションである。
>> コマンド chmod *

オプション
-f すでにリンクが張られていたら、リンクを付け替える。
% ln -s file link
% ln -s file2 link
ln: link: File exists
このようにリンクの「張り替え」のような作業をするとエラーとなるが -f オプションを付けると、この「張り替え」ができるようになる。
-s シンボリックリンクを張る。-s を付けないとハードリンクとなる。

locate ファイルをデータベースから検索する。

例えば locate a は
% find / -name '*a*' -print
と同じ働きをする。つまり、全ファイルシステムの中から、a という文字を含むファイル・ディレクトリ名を検索し、表示する。

しかし find と違い、locate はその場でディレクトリを検索するのではないので検索時間がかからない。あらかじめファイルシステム中の全ファイルをデータベースに記録しておき、そのデータベースを検索するので、数秒で検索が終了する。欠点は、データベースが更新された後にファイルの移動などをした場合、その情報がデータベースに反映されないことである、

FreeBSD の場合は、/etc/periodic/weekly/310.locate というスクリプトが週に1回実行され、その中で /usr/libexec/locate.updatedb が呼ばれて/var/db/locate.database が更新される。つまり週に一度だけデータベースが更新されることになる。なお、/etc/periodic/ を実行するのは cron デーモンである。
>> コマンド cron *

OS インストール直後はデータベースファイルが作成されていないので、直接 /usr/libexec/locate.updatedb を実行すればよい。本当は nobody 権限で実行するのが一番よいが、locate.updatedb(8) を参照。

なお、/etc/locate.rc を書き換えることで、あるディレクトリ以下は検索対象に含めない、という設定をすることもできる。
>> 読み方 locate *

lock ターミナルをロックする。

実行するとパスワードを要求される。再びそのパスワードが入力されるまで入力を受け付けない。
% lock
Key: (ロックのキーを入力)
Again: (もう一度同じキーを入力)
lock: /dev/ttyp2 on localhost. timeout in 15 minutes
time now is Fri Jan 23 21:32:09 JST 1998
Key: (ここでキーを入力するとロック解除)

例えば kterm 内で lock を実行すると、ロックされるのは kterm 内だけである。X を使っていて画面全体をロックしたい場合は xlock を使うとよい。
>> コマンド xlock *

look 英単語のつづりを調べる。

例えば「レシーブ」のつづりが「receive」「recieve」「reseive」のどれが正しいかわからない場合、
% look reseive
⇒ 何も出力されない (=そんな英単語はない)
% look recieve
⇒ 何も出力されない (=そんな英単語はない)
% look receive
receive
received
receivedness
receiver
receivership
⇒ 出力された。
となるため receive が正しいことがわかる。辞書は (FreeBSD の場合は) /usr/share/dict/words に置かれている。

ls ファイル・ディレクトリを表示

ファイル・ディレクトリの一覧を表示する。ファイルを指定せず
% ls
とすると、カレントディレクトリにあるファイル・ディレクトリを表示する。
% ls file1 file2 file3
だと、指定したファイルの一覧を表示する。
% ls file? *.txt
などと、ワイルドカードを使うこともできる。詳細な情報を見たい場合は
% ls -l file1 file2 file3
とすればよい。
% ls dir1 dir2 dir3
のように、ディレクトリ名を指定すると、指定したディレクトリの下にあるファイル・ディレクトリを表示する。(ディレクトリの下ではなく)ディレクトリ自体の情報を見たいなら、
% ls -d dir1
とする。また、ls は「.」から始まるファイル・ディレクトリは表示しない。-a や -A オプションを使うことで「.」から始まるファイルも表示させることができる。

必ず覚えておきたいのは、-l、-A オプション。覚えておくと便利なのは -F オプション。当ページ管理人は
% alias ls "ls -F"
% alias l "ls -lFA"
としている。これは csh・tcsh の書き方。sh・bash を使っているなら
% alias ls="ls -F"
% alias l="ls -lFA"
とすればよい。
>> コマンド alias *

-a 「.」 から始まるファイルも表示。「.」「..」も表示する。
-A 「.」 から始まるファイルも表示。「.」「..」は表示しない。
root が ls を実行した場合、常に -A オプションが付けられたものとして動作する。
-l ファイル、ディレクトリの詳細な情報を表示する
-T タイムスタンプを年月日時分秒まで表示 (要 -l オプション)
-o ファイルフラグを表示。BSD 系のみ (要 -l オプション)
>> コマンド chflags *
-1 (マイナスエルじゃなくてマイナスイチ) 1行につき1つのファイルの情報を表示
-C マルチカラムで表示 (-1 の逆)。
% ls | more
などとすると、ls が出力先がパイプだと判断し、自動的に -1 を指定したのと同じように動作するが、-C を付けるとそれを抑制し、1行に複数のファイルを表示する。
-F ファイルタイプの識別子を付ける。
ディレクトリの後ろに「/」、シンボリックリンクの後ろに「@」、実行形式ファイルの後ろに「*」をつける
-L シンボリックリンク自体ではなく、リンク先のファイルの情報を表示
-R 再帰的にディレクトリ以下のファイルを表示する。
つまり ls -R / で全てのファイルが表示されることになる
-c ファイルの変更日時ではなく、最後にファイルステータスを変更した日時を表示
>> 用語集 タイムスタンプ *
-u ファイルの変更日時ではなく、最後にファイルにアクセスした日時を表示
>> 用語集 タイムスタンプ *
-d ディレクトリを指定した場合、ディレクトリ以下のファイルではなくディレクトリ自体の情報を表示。
ls -l /usr/bin は、ls -l /usr/bin/* と同じような動作をするが、ls -ld /usr/bin だと、
drwxr-xr-x 2 bin bin 5120 Oct 7 05:26 /usr/bin
と、ディレクトリ自体の情報を表示する
-f ファイル名をソートせずに表示
-r 逆順にソートして表示
-t ファイルを変更した日時の順でソートする。最近どのファイルが更新されたか調べたいときは
% ls -lt | head
最近どのファイルが参照されたかを調べたいときは
% ls -lut | head
が便利。
-i ファイルの i-node を表示
>> コマンド ln *
-s 各ファイルのファイルシステムブロックの使用量を表示 (512バイト単位)
たとえ1バイトのファイルでも1ブロック (512バイト) を消費している。その消費量を表示する。ブロックの単位は環境変数 BLOCKSIZE で設定できる。
>> 環境変数 BLOCKSIZE *
>> 用語集 穴あきファイル *
-k -s オプションが指定された場合、使用量を 1K バイト単位で表示する
-x ファイルを横方向ではなく、縦方向にソートする
(-x オプションは SystemV 系と GNU の ls のみ)。
-q ファイル・ディレクトリ名の中に表示不可能な文字があった場合、`?' という文字に置き換えて表示する。このオプションはデフォルトで有効になっている。このおかげで日本語を含むファイル名を ls で表示しようとすると、???? などとなってしまう。この機能は、出力先がパイプやファイルだと抑制されるので、
% ls | less
% ls | cat
などとすると、日本語ファイル名を表示できる。
>> コマンド stat *
>> 読み方 ls *

lsdev 現在のシステムで有効なデハイスを表示

-t class 指定したタイプのデバイスを表示。
class に指定できるのは、cpu、isa、eisa、pci、scsi、disk、bus。
-c カーネル設定ファイルと同じような書式で出力

lsof オープン中のファイル一覧や、ファイルをオープンしているプログラムの一覧を表示

>> コマンド fuser *   fstat *
>> 読み方 lsof *

lynx テキストブラウザ

起動時に
% lynx http://www.foo.com/~bar/index.html
とコマンドラインで URL を与えると、指定したページを表示する。ローカルファイルを
% lynx dir/index.html
としてもよい。

起動後はカーソルキーの上下で移動し、リターンキーでリンク先へジャンプする。Ctrl-n、Ctrl-p で前後に1行ずつスクロールする。カーソルキーの左右で、直前に見ていたページに移動できる。

lynx は国際化されているが、デフォルトで日本語を表示すると化けてしまう。日本語を表示させるには、lynx を起動して O)ption、C)haracter set として Japanese(EUC) を選択する。選択後に「>」を押すと設定を ~/.lynxrc にセーブする。

-source URL 指定のURLを読みこみ、標準出力に書き出す。
% lynx -source http://www.foo.com/~bar/index.html
% lynx -source http://www.foo.com/~bar/sample.jpg > sample.jpg

HTTP proxy の設定は、環境変数 HTTP_PROXY で設定できる。
>> コマンド mosaic *   netscape *
>> 環境変数 HTTP_PROXY *
>> 読み方 lynx *

m4 マクロ言語プロセッサ

m4 は cpp のように文字列の置き換え・ファイル取り込みなどを行うマクロ言語プロセッサである。m4 は cpp より強力だが、その分わかりづらい。m4 を詳細に説明すると本が一冊書けてしまうので、概要だけ述べる。

まずはコマンドラインから m4 を実行してみよう。m4 が何の役に立つかわからない人はつまらなく思うかもしれないが、最初に基本的な機能だけは抑えておくと理解しやすい。

入力行は便宜的に「>」を付けたが、実際にはこのようなプロンプトは表示されない。
% m4
> hoge
hoge
⇒ hoge を入力したら hoge が出力された。m4 の最も基本的な機能は、入力をそのまま出力することである。
> define(hoge, `fuga')
⇒ マクロ hoge を定義。入力に hoge を発見したらfuga に置換するということ。fuga を囲むクォートは '〜' ではなく `〜' (バッククォートとシングルクォート) であることに注意。
> hoge
fuga
⇒ マクロ hoge を定義したため、fuga に置換された
> hogehoge
hogehoge
⇒ hogehoge は fugafuga とはならない。m4 は単純に文字列を置換するわけではない。なぜなら、hogehoge は hoge と hoge が連続したものとは見なされず、hogehoge というひとつの入力 (正確にはトークン) と見なされる。
> hoge hoge
fuga fuga
⇒ 空白で区切れば別のトークンとなるので、hoge hoge は fuga fuga に置換される。
> define(abc, `hoge')
⇒ マクロ abc を定義。abc は hoge に置換される。
> abc
fuga
⇒ abc は hoge ではなく fuga となっていることに注意。
define(hoge, `fuga')
define(abc, `hoge')
という 2つのマクロ定義により、abc → hoge → fuga となる。つまりマクロ展開後の文字列がマクロと見なせる場合、再度マクロ展開が行われる。これ以降はマクロと展開後の文字列を混同しないよう、マクロ名は「アンダーバー + 大文字」に統一する。
> define(_ARGS, `args are $1 $2')
⇒ マクロには引数を渡すことができる。マクロ定義部では $1・$2… で 1番目・2番目… の引数を扱うことができる。
> _ARGS(`aaa')
args are aaa
> _ARGS(`aaa', `bbb')
args are aaa bbb
> _ARGS(`aaa', `bbb', `ccc')
args are aaa bbb
⇒ マクロ _ARGS では 2つの引数しか使用していないため、3つ目以降の引数は無視される。
> define(_ARGS, `args are $* [$#]')
⇒ 全ての引数を表すには $* を、引数の数は $# を使う。ちなみにこれは上で定義したマクロ _ARGS を再定義していることになる。
> _ARGS(`aaa', `bbb', `ccc', `ddd')
args are aaa bbb ccc ddd [4]
⇒ 全ての引数と、引数の個数に展開されている。

m4 にはいくつかの組み込みマクロがあらかじめ用意されている (define もその一つ)。
> include(`hoge.txt')
⇒ ファイル hoge.txt を取り込む。もしファイルが存在しなければエラー。ファイル内容もマクロとして評価されることに注意。
> syscmd(`コマンド')
⇒ コマンドを実行した結果を取り込む。

コマンドラインからマクロ定義をいちいちタイプしたくないだろうから、ファイル (この例では input.txt) に
define(_HOGE, `fuga $1')
_HOGE(`abc')
と入力内容とマクロ定義をあらかじめ記述しておき、
% m4 input.txt > output.txt
としてマクロ展開を行うのが一般的な使い方である。

もし入力内容とマクロ定義を分離しておきたければ、適当なファイル、例えば input.m4 に
define(_HOGE, `fuga $1')
とマクロ定義を記述し、入力ファイル内で
include(`input.m4')
_HOGE(`abc')
とマクロ定義ファイルを include すればよい。こうすることで、一つだけマクロ定義ファイルを作成しておいて、複数の入力ファイルで使いまわすことができる。

より実践的な例として、HTML を m4 で生成してみよう。当ページ管理人は HTML ファイルを手で書いているわけではない。エディタで
のようなプレインテキストを作成し、これを自作の Perl スクリプトに喰わせることで
という HTML ファイルを自動生成している。

自作スクリプトの主な機能は以下の通り。
  • 「:start ほげほげ」と書けば HTML・HEAD・TITLE・BODY 要素が出力され、「ほげほげ」がページタイトルとなる
  • 「:term ふがふが」と書けば項目の見出しとなる
  • 「:cmd」〜「:cmd」で囲むとコマンドの実行例として表示される
  • 「:code」〜「:code」で囲むとソースの例として表示される
  • 「:preincude ファイル名」と書くとソースファイル全体が取り込まれる
  • このとき、ソースに行番号を付加する
  • さらにソース中の <・> を &lt;・&gt; に置換する (実体参照化)
  • 「:preincude ファイル名 42-45」と書くとソースファイル中の指定した行番号部分が取り込まれる
  • 「:preincude 42-45」とファイル名を省略すると、前回指定したファイル名が取り込まれる
  • ファイルの終わりには自動的に cvs の $id: ヘッダや BODY・HTML 要素の閉じタグが出力される

上記の細かな仕様はどうでもよい。これと同じことを m4 を使って実現してみよう、というのが目的である。

結果として、以下の機能変更を行った。