UNIX/Linuxコマンドマニュアル

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 用。

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

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

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 アカウント情報ログファイル作成の許可/禁止

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

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

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 コマンドを使う。
>> OSオンラインマニュアル(man) FreeBSD adduser(8)
>> OSオンラインマニュアル(man) Linux adduser(8)

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 &
とすると、タイトルバーやメニューに日本語が表示できる。

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 ファミリーの仲間とは言えない。

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

UNIX/Linux の alias コマンドを使うと、あるコマンドを別のコマンド名で登録して、長いコマンド名の別名・短縮形を作ることができる。引数を処理することもできる。


alias コマンドは csh・tcsh や、sh・bash などのシェルの内部コマンドである。*BSD で主に使用されている csh・tcsh と、Linux で使用されている bash では書き方が異なるので、注意して読んでほしい。

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

CentOS + bash の場合、以下のようになった。
% alias
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

FreeBSD + tcsh の場合、以下のようになった。
% alias
h (history 25)
j (jobs -l)

csh・tcsh の場合
csh・tcsh の場合は以下のように設定する。
% alias ls "ls -lFA"
% alias du "du -k"
% alias memo "emacs ~/memo.txt"
% alias f "find / -name '\!*' -print"

sh・bash の場合
sh・bash の場合は、「=」で結ぶ。
% alias ls="ls -lFA"
% alias du="du -k"

alias の一時的な無効化
csh・tcsh・sh・bash とも、コマンドの前に `\' を付けることで、一時的にエイリアスを解除できる。
% alias ls "ls -lFA" (csh・tcsh の場合)
% alias ls="ls -lFA" (sh・bash の場合)
% ls (ls -lFA と同じ)
% \ls (alias が無効。普通の ls と同じ)
また、/bin/ls などとフルパスで書くことでエイリアス設定を回避できる。
% /bin/ls (alias が無効。普通の ls と同じ)
% ls (ls -lFA と同じ)

エイリアスの削除 (恒久的な無効化)
エイリアスを削除 (解除) するには unalias を使う。

tcsh の引数処理
tcsh では 以下のように引数を渡すことができる。これは引数全体を find に渡す例。
% alias em "emacs \!*"
% em a.txt b.txt
→ emacs a.txt b.txt と同じ
続いて、1個目の引数・2個目の引数、と指定した場合。
% alias fx "find \!:1 -type f | xargs grep \!:2 /dev/null"
% fx . abc
→ find . -type f | xargs grep abc /dev/null と同じ
bash の alias での引数処理はどうやってもできないので、function で関数を作ろう。

bash の拡張機能
bash の場合、alias で設定した文字列の末尾にスペースを入れておくと、次の引数も alias 展開される。大変わかりづらいが、要はこういうことだ。
% alias MYCMD="cal"
% alias sudo="sudo -E"
→ 末尾に空白をいれない場合は…
% sudo MYCMD
→ cal に展開されない
% alias sudo="sudo -E "
→ 末尾に空白をいれておくと…
% sudo MYCMD
→ MYCMD が cal に展開される
sudo や nice コマンドのように、第2引数にコマンド名を渡すものに設定すると便利かもしれない。

注意: alias はシェルスクリプト内では使えない
一般的に、alias はシェルスクリプト内や crontab 内では使えない。なぜならば、ある環境の ~/.cshrc や ~/.bashrc などで
alias ls="ls -lFA"
などと alias 設定していたとして、もしシェルスクリプト実行時に alias が有効になる場合、/bin や /usr/bin にあるシェルスクリプトも上記の alias 設定が効いてしまうため、ls を実行するつもりが ls -lFA を実行してしまい、誤動作につながるためである。

csh や tcsh では、
#!/bin/csh -f
と -f オプションを付けることで .cshrc などの読み込みが抑止され、結果的に alias が未設定の状態でシェルスクリプトが動くことになる。alias の機能が無効になっているわけではないので、スクリプト内で
#!/bin/csh -f
alias ls "ls -lFA"
ls
とすれば、alias は機能する。

bash では、非インタラクティブで起動した場合は alias の展開が無効化される。
#!/bin/bash
alias ls="ls -lFA"
ls
とすると、ls -lFA ではなく、ls が実行される。下記のように expand_aliases を有効にすることで、alias 展開が有効化され、ls -lFA が実行されることになる。
#!/bin/bash
shopt -s expand_aliases
alias ls="ls -lFA"
ls

しかしながら、シェルスクリプト内で alias を使うことは、普通は行わないものであることには留意いただきたい。

設定ファイル
毎回 alias を手で打つのはめんどくさいので、普通 alias の設定は、~/.cshrc や ~/.profile などに記述しておく。こうすることで、ログインすると自動的に alias が有効になる。

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

-q メッセージを表示しない

apache 高機能WWWサーバ

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

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

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

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 コマンドは表示されない。

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
(略)
>> OSオンラインマニュアル(man) Linux ar(1)
>> OSオンラインマニュアル(man) FreeBSD ar(1)
>> OSオンラインマニュアル(man) FreeBSD ar(5)
>> OSオンラインマニュアル(man) Solaris10 ar(1)

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

archieについての詳しい説明は xarchie へ。

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

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

as アセンブラ

C をコンパイルする場合は、cc が自動的に as を呼んでくれる。
>> OSオンラインマニュアル(man) FreeBSD as(1)
>> OSオンラインマニュアル(man) Solaris10 as(1)
>> OSオンラインマニュアル(man) Linux as(1)

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

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

% at 10am -f foo.sh
⇒ 午前10時にシェルスクリプト foo.sh を実行
% echo ls | at 4pm + 2 days
⇒ 2日後の午後4時に ls を実行
>> OSオンラインマニュアル(man) Linux at(1)
>> OSオンラインマニュアル(man) FreeBSD at(1)
>> OSオンラインマニュアル(man) Solaris10 at(1)

atq 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 の勉強をした方がよいだろう。
>> OSオンラインマニュアル(man) Solaris10 awk(1)
>> OSオンラインマニュアル(man) FreeBSD awk(1)

banner 大きい文字を出力

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

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

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

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

FreeBSD では -w オプションで文字幅を指定できるので活用しよう。
% banner -w 28 hoge
       #                 #
       ###################
       ###################
                 #
                 #
       ###########
       ##########
           ###
        #########
       ##       ##
       #         #
       #         #
       ###     ###
         #######
   ##        ##
 ##   ###  ######
 #    ### ##    ##
 #   ###  #      #
 #   ###  ##    ##
 ######    #######
                  ##
           ###
        #########
       ##   #   ##
       #    #    #
       #    #    #
        #   #####
            ####
>> OSオンラインマニュアル(man) Solaris10 banner(1)
>> OSオンラインマニュアル(man) Linux banner(6)

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

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

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

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 の説明を参照。
>> OSオンラインマニュアル(man) Linux basename(1)
>> OSオンラインマニュアル(man) Linux basename(3)
>> OSオンラインマニュアル(man) FreeBSD basename(1)
>> OSオンラインマニュアル(man) Solaris10 basename(1)

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

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

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

bash という名前は Bourne-Again SHell の頭文字を取ったもの。sh の作者がボーン (Bourne) 氏 であることから、Bourne と Born (生まれる) をかけて、「生まれ変わったシェル」として命名された。

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 回掛け合わせた数。
>> OSオンラインマニュアル(man) Solaris10 bc(1)
>> OSオンラインマニュアル(man) FreeBSD bc(1)
>> OSオンラインマニュアル(man) Linux bc(1)

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 にバイナリが置かれる。

bdftopcf 

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 に書いてある (英文)。

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 を参照。

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 はなぜ動く?
>> OSオンラインマニュアル(man) FreeBSD biff(1)
>> OSオンラインマニュアル(man) Linux biff(1)

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 に後方インクリメンタルサーチが割り振られている。

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

yacc の上位互換プログラム。GNU が作成・配布している。

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 の後継であるディスクベンチマークプログラム。機能的な差異は以下の通り。
  • 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

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 バイナリパッチ適用

詳細は bsdiff を参照。

builtins 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 としても全く同じである。

他の圧縮・伸長コマンドや、マルチコア対応版については下記項目を参照のこと。
>> OSオンラインマニュアル(man) FreeBSD bzip2(1)
>> OSオンラインマニュアル(man) Linux bzip2(1)

cal カレンダーを表示する

cal コマンドを引数なしで実行すると、その月のカレンダーを表示する。
% cal
   September 2016
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
環境によっては、曜日などが日本語で表示されるかもしれない。
日本語・英語で出し分けしたい場合、下記のように LC_TIME 環境変数に ja_JP.utf8 や C などを設定してみよう。
% env LC_TIME=ja_jp.utf8 cal
      9月 2016
日 月 火 水 木 金 土
             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

% env LC_TIME=C cal
   September 2016
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年のカレンダーを表示」となる。
% cal 1998
⇒ 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 (略)
数字をふたつ指定すると、「y年m月のカレンダーを表示」となる。
% cal 6 1999
⇒ 1999年6月のカレンダーを表示
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 % 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

cal コマンドのオプション
▷ -y オプション
今年のカレンダー(1〜12月)を表示
▷ -j オプション
1月1日からの日数を表示する
% cal -j
       September 2016
Sun Mon Tue Wed Thu Fri Sat
                245 246 247
248 249 250 251 252 253 254
255 256 257 258 259 260 261
262 263 264 265 266 267 268
269 270 271 272 273 274
▷ -3 オプション
先月・当月・翌月の 3ヶ月のカレンダーを表示する (Linux のみのようだ)。
     August 2016         September 2016         October 2016
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  5  6               1  2  3                     1
 7  8  9 10 11 12 13   4  5  6  7  8  9 10   2  3  4  5  6  7  8
14 15 16 17 18 19 20  11 12 13 14 15 16 17   9 10 11 12 13 14 15
21 22 23 24 25 26 27  18 19 20 21 22 23 24  16 17 18 19 20 21 22
28 29 30 31           25 26 27 28 29 30     23 24 25 26 27 28 29
                                            30 31
▷ -m オプション
日曜始まりではなく、月曜始まりのカレンダーを表示する (Linux のみのようだ)。
% cal -m
   September 2016
Mo Tu We Th Fr Sa Su
          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

ちなみに 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
>> OSオンラインマニュアル(man) Linux cal(1)
>> OSオンラインマニュアル(man) Solaris10 cal(1)
>> OSオンラインマニュアル(man) FreeBSD cal(1)

calc 簡易計算機

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

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

cat コマンドの基本的な使い方
% cat sample.txt
→ sample.txt の内容を表示する
% cat > sample.txt
hogehoge
(Ctrl-d で終了)
→ エディタを開くまでもない文字列をファイルに書き込む場合。

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

ファイルの結合
cat コマンドは、split コマンドで分割したファイルを結合するときにも使われる。
% split sample
% ls x??
xaa xab xac
% cat xaa xab xac > sample2
>> OSオンラインマニュアル(man) Solaris10 cat(1)
>> OSオンラインマニュアル(man) FreeBSD cat(1)
>> OSオンラインマニュアル(man) Linux cat(1)

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 を実行する。
とするとよいだろう。
>> OSオンラインマニュアル(man) FreeBSD catman(1)
>> OSオンラインマニュアル(man) Solaris10 catman(1M)
>> OSオンラインマニュアル(man) Linux catman(8)

cc C コンパイラ

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

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

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 -
と等価である。

cda CDプレイヤー

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 など)、引数なしで起動すると対話モードに入るので、そこで命令を書いてもいい。

cdplay CDプレイヤー

起動方法は以下の通り。
% cdplay デバイス名

cdplayer CDプレイヤー

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

chdir カレントディレクトリを変更する。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 のみだろうと思われる。
>> OSオンラインマニュアル(man) FreeBSD chflags(1)

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

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

chmod ファイル・ディレクトリのパーミッション・属性を変更する。

UNIX/Linux の 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 コマンドによるパーミッションの変更方法
chmod コマンドを使うことで、パーミッションを変更することができる。なお、パーミッションを変更できるのは、そのファイル・ディレクトリの所有者か、root のみである。

パーミッションの指定方法には絶対方式と相対方式がある。絶対方式は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 コマンドなどで、その下に存在するファイルの一覧を取得できる。具体的には、readdir(2) できる。
  • ディレクトリに「w」が設定されていると、ディレクトリの下にファイルを新規作成できるし、ディレクトリの下に存在するファイルを rm コマンドで削除できる。具体的には、ディレクトリの下のファイル・ディレクトリに対して stat(2) や unlink(2) ができる。
  • ディレクトリに「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
さて、先に少し触れたが、
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 の項を参照してほしい。

ディレクトリに対する setgid
ディレクトリに対する 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 と同じ挙動をさせることができる (grpid または bsdgroups)。

sticky bit
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 コマンドで設定できる。
>> OSオンラインマニュアル(man) Solaris10 chmod(1)
>> OSオンラインマニュアル(man) FreeBSD chmod(1)
>> OSオンラインマニュアル(man) Linux chmod(1)
>> OSオンラインマニュアル(man) Linux chmod(2)

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 である。
>> OSオンラインマニュアル(man) FreeBSD chown(8)
>> OSオンラインマニュアル(man) Solaris10 chown(1)
>> OSオンラインマニュアル(man) Linux chown(1)
>> OSオンラインマニュアル(man) Linux chown(2)

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

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

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

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

ログインシェルとして指定できるのは /etc/shells の中に書かれているものだけである。
>> OSオンラインマニュアル(man) FreeBSD chpass(1)

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

FreeBSD では chsh は chpass と全く同じである。説明は chpass の項を参照。
>> OSオンラインマニュアル(man) Linux chsh(1)

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

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

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

clear 端末画面の消去

clear コマンドは、端末を消去 (クリア) するコマンドである。端末が文字化けしてなおらない場合は、reset コマンドを試すとよい。

FreeBSD では clear はシェルスクリプトで、内容は
#!/bin/sh -
exec tput clear
となっている。
>> OSオンラインマニュアル(man) Linux clear(1)
>> OSオンラインマニュアル(man) Solaris10 clear(1)

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

cmp はあまり多機能ではないので、2つのファイルが違うものかどうかを知りたいときだけ使うといいだろう。
>> OSオンラインマニュアル(man) Linux cmp(1)
>> OSオンラインマニュアル(man) FreeBSD cmp(1)
>> OSオンラインマニュアル(man) Solaris10 cmp(1)

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 パッケージ内に含まれている。

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'
と等価である。

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

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

comm は比較対象ファイルがあらかじめ辞書順にソートされている必要がある。普通はいちいちソートするのは面倒なので、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 で指定したファイル群は補完対象から外される。

compress ファイルを圧縮する

圧縮ファイル名は元ファイル名の最後に .Z を付けたもの。昔はよく使われていたが、今はより圧縮率の高い gzip や bzip2 があるので、特に理由がないなら 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 を使うとよい

少なくとも Linux においては compress は標準配布物ではなく、ncompress パッケージを別途インストールする必要がある。

他の圧縮・伸長コマンドや、マルチコア対応版については下記項目を参照のこと。
>> OSオンラインマニュアル(man) Solaris10 compress(1)
>> OSオンラインマニュアル(man) FreeBSD compress(1)

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 などが消去される。

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

convert コマンドは、ImageMagick というパッケージに含まれる画像変換コマンドである。フォーマット変換・リサイズ・切り出し等が行える。FreeBSD・Linux 等、多くの UNIX 系 OS では imagemagick というパッケージをインストールすることで使用することができる。


ImageMagick バージョン7 以降の注意点
ImageMagick バージョン7 より、convert 等のコマンドがなくなり magick コマンドに変更されている。Windows で関係ない convert コマンドが存在し、混乱を招くため。2017年9月現在、FreeBSD では ImageMagick がバージョン6、ImageMagic7 がバージョン7 として ports/packages が用意されている。

フォーマット変換
どのフォーマットに変換するかは、指定した拡張子から自動的に判別してくれる。
% convert sample.gif sample.jpg
⇒ GIF 形式の sample.gif から JPEG 形式の sample.jpg に変換する
一括変換したい場合は mogrify コマンドを使う。
% mogrify -format png *.jpg
⇒ JPEG ファイルを PNG 形式に変換する。拡張子 .png で新しいファイルが生成される。

リサイズ (拡大・縮小)
resize オプションを使うとリサイズができる。標準では元画像の縦横比を「維持する」ことに注意。
また、拡大するか縮小するかは指定するサイズ次第である。
% convert -resize 100x200 from.png to.png
→ 100x200 の箱に収まるよう、縦横比を維持して変換する。元画像が 40x80 であれば拡大するし、200x400 であれば縮小する。
% convert -resize 100x from.png to.png
→ 横が 100ピクセル内に収まるよう、縦横比を維持して変換する。
% convert -resize x200 from.png to.png
→ 縦が 200ピクセル内に収まるよう、縦横比を維持して変換する。
% convert -resize 50% from.png to.png
→ 縦横それぞれが 50% の長さになるよう縮小する。
% convert -resize 150% from.png to.png
→ 縦横それぞれが 150% の長さになるよう縮小する。

縦横比が変わってもよいのでとにかく指定したサイズに変換したい場合は、以下のようにサイズの末尾に "!" を付ける。
% convert -resize 100x200! from.png to.png

サイズが不揃いな画像が複数あり、大きすぎる画像はあるサイズに縮小したいが、そのサイズ未満の場合は拡大はしない、としたい場合は、下記のように末尾に ">" を付ける。
% convert -resize '100x200>' from.png to.png
その逆で、小さすぎる画像は拡大したいが、大きい画像は縮小しないとする場合は、末尾に "<" を付ける。
% convert -resize '100x200<' from.png to.png

上書きで一括変換したい場合、mogrify コマンドを使う (元のファイルは残らない)。
% convert -resize 100x200! from.png to.png

アニメーション GIF 生成・分割
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 という画像ファイルを生成する

EXIF 情報等を削除する
画像ファイルに埋め込まれた EXIF 情報を削除するには strip オプションを使う。
% convert -strip from.jpg to.jpg
一括して上書き保存したい場合は mogrify -strip を使う (元のファイルは残らない)。
% mogrify -strip *.jpg

convmv ファイル名のエンコーディングを変換する。

ファイル名のエンコーディングを変換する (ファイル内容ではなく、ファイル名のエンコーディングであることに注意)。

例えば UNIX で UTF-8 のファイル名で zip アーカイブを作成し、Windows にて展開すると、Windows のエクスプローラでは文字化けしてしまう。そのようなときに convmv コマンドにてファイル名のエンコーディングを Shift_JIS に変えておく、などといった使い方をする。

convmv はファイル名を実際にリネームしてしまうので、実行後は変換元ファイル名ではアクセスできなくなる。慣れないうちは、変換元ファイルのバックアップをとっておくとよいだろう。


実行例
% convmv -f utf8 -t shift_jis *.txt
→ *.txt のファイル名を UTF-8 から Shift_JIS に変換するが、実際に変換せず表示のみ。
% convmv -f utf8 -t shift_jis *.txt --notest
→ --notest オプションを指定することで、実際にファイル名が変更される。

オプション
-f 変換元のエンコーディングを指定する。
-t 変換先のエンコーディングを指定する。
-r ディレクトリ配下までたどって変更する。-r を指定しない場合はディレクトリをたどらない。
--notest 実際にファイル名を変更する。--notest を指定しない場合は、表示のみ。
--list 使用可能なエンコーディングの一覧を表示する。この出力からエンコーディングを選んで、-f や -t に指定する。

cp ファイルをコピーする

UNIX/Linux における cp コマンドは、ファイルをコピーするコマンドである。cp コマンドは古くから存在するため (最初の UNIX である V1 で登場)、あらゆる UNIX/Linux 系 OS で使用可能である。

cp コマンドの基本的な使い方
% cp sample1.dat sample2.dat
⇒ sample1.dat を sample2.datにコピー
% cp sample1.dat dir/
⇒ sample1.dat をディレクトリ dir/ の下に、同じ名前のままコピー
% cp sample1.dat dir/sample2.dat
⇒ sample1.dat をディレクトリ dir/ の下に、sample2.dat としてコピー
% cp sample1.dat sample2.dat sample3.dat dir/
⇒ sample1.dat・sample2.dat・sample3.dat をディレクトリ dir の下にコピー

オプション
-i コピー先のファイルが存在する場合、上書きしてよいか確認を求める。
操作に慣れていないうちは、
alias cp "cp -i" (csh・tcsh の場合)
alias cp="cp -i" (sh・bash の場合)
を設定しておくとよい。
-f 上書き確認を行わない。
-f オプションはデフォルトだが、alias cp cp -i としている場合に、一時的に alias を無効にする場合に -f オプションを使うと便利。
-p または --preserve
パーミッション・オーナー・グループ・タイムスタンプもそのままコピーする
-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
というファイルができる。

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

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
使ったことがないので、何とも言えず。
>> OSオンラインマニュアル(man) FreeBSD cpp(1)
>> OSオンラインマニュアル(man) Solaris10 cpp(1)
>> OSオンラインマニュアル(man) Linux cpp(1)

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 コマンドを参照。
>> OSオンラインマニュアル(man) Linux cron(8)
>> OSオンラインマニュアル(man) FreeBSD cron(8)

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

UNIX/Linux の crontab コマンドは定期的に実行するコマンドを登録・確認・管理するコマンドである。

UNIX・Linux では cron または crond というデーモンが常時起動しており、指定の時刻になると指定のコマンドを実行してくれる。crontab コマンドを使うと、その設定ファイルを表示・設定・更新・削除することができる。


crontab 設定方法
日時を指定して、自動的にコマンドを実行することができる。設定方法は
% crontab -e
とすると、エディタが起動して設定内容を更新することができる。エディタは環境変数 EDITOR で自由に設定することができる。しかしながら、e をタイプするつもりが隣の r を押してしまうと、crontab -r で設定内容がクリアされてしまう。当ページ管理人は「crontab -e を使うな」と声を大にして言いたい。

おすすめは、~/.crontab や crontab.txt などのファイルを作り、その中に設定内容を記述した上で、
% crontab 設定ファイル名
→ FreeBSD・Linux の場合
% crontab < 設定ファイル名
→ Solaris の場合
とする方法である。当ページ管理人は、~/.crontab というファイルを作り、このファイルをエディタで編集してから、
% crontab ~/.crontab
として cron に反映する方法を好む。ただし、この方法だと cron に登録されているデータと ~/.crontab の内容が一致している保証はない、という欠点がある。

設定ファイル書式
設定ファイルの書式は
分 時 日 月 曜日 コマンド
である。それぞれの書式は下記のとおり。
分 0-59
時 0-23
日 1-31
月 1-12
曜日 0-7 (0:日曜、1:月曜、2:火曜、3:水曜、4:木曜、5:金曜、6:土曜。7 は 0 と同じ日曜)
それぞれの値は、カンマで結合することで複数指定することができる。例えば「時」のカラムを "6,12,18" とすると、6時・12時・18時を指定できる。また、"2-10" などで範囲指定ができる。さらに FreeBSD・Linux などの一部の crontab では「6-18/2」「*/3」などと、
スラッシュを使うことで「N日おき」「N時間おき」「N分おき」といった指定ができる。
いくつかの例を下記に示す。
* * * * * command
⇒ 1分おき (毎分) に command を実行する。
10 3 1 * * command
⇒ 毎月1日の3時10分に command を実行する。
0 12 * * 0 command
⇒ 毎週日曜日の12時に command を実行する。
0 0,4,8,12,16,20 * * * command
⇒ 0時0分・4時0分・8時0分・12時0分・16時0分・20時0分 に command を実行する。
0 */4 * * * command
⇒ 上記と同じことは "*/4" と書いてもよい ("*/4" は 4時間おきの意味)
10 6-20 * * * command
⇒ 6時〜20時の間、毎時10分に command を実行する (6時10分〜20時10分)。
10 6-20/2 * * * command
⇒ 6時〜20時の間、2時間おきに、毎時10分に command を実行する (6時10分・8時10分〜18時10分・20時10分)。

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

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

crontab コマンドのオプション一覧
  • -l 現在設定されている crontab データを表示する
  • -r 現在設定されている crontab データを削除する。
  • -r 現在設定されている crontab データを編集する (エディタが起動する)。
  • -u [ユーザ名] 一般ユーザで crontab コマンドを実行する場合、自分自身の crontab データのみ表示・修正することができる。root で他ユーザの crontab データを更新したい場合、-u オプションでユーザを指定する。
# crontab -u yamada -e
→ ユーザ yamada の crontab データを修正する。
# crontab -u yamada -r
→ ユーザ yamada の crontab データを削除する。

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

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

前処理のプログラムが正常終了した場合のみ、次のプログラムを実行したい場合は、
* * * * * command1 && command2
とする。
前処理プログラム A と B を並列実行し、A・B 両方が終了したらプログラム C を実行するには
* * * * * (commandA & commandB & wait) && commandC
とする。

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

秒単位での指定
cron では、1分より細かい単位で実行することはできない。もし 30秒ごとにコマンドを実行したい場合は
* * * * * command
* * * * * sleep 30 ; command
などと書けばよい。

@reboot で OS 起動時の処理
一部 cron 実装 (vixie-cron の系統を採用している FreeBSD・Linux 等) では、@reboot という書き方によって、OS 起動時に任意の処理を行うことができる。
@reboot command1
ただし、OS 起動だけではなく crond (デーモン) が起動した際、例えば
# service crond restart
などとした際に @reboot が発動するかは実装によるので確認してほしい。

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

注意点: 日と曜日指定は OR である
極めてわかりづらいのだが、日と曜日の組み合わせだけは「OR」である。
0 0 1 * 2 command1
は、毎月1日の 0時0分と、毎週火曜日の 0時0分に実行される。よって、crontab の通常書式だけでは「13日の金曜日」を表現することはできない。当ページ管理人のネット上の観測によると、これにハマる人はとても多いようなので要注意である。

注意点: 年の指定
crontab で年の指定はできない。「今年のある処理は2017年3月18日に起動するが、来年は未定。そもそも来年実行するかどうかも未定」となったとしても、
0 0 18 3 * command
と年なしで書かなくてはならない。来年忘れそうで不安である。そういときは
0 18 3 * [ `date +\%Y` -eq 2017 ] && command
としてはどうか。上記コードは未テストなので注意。
注意点: 誤って毎分起動
毎日12時に起動しようとして、
0 12 * * * command
と書くつもりが、
* 12 * * * command
と書いてしまい、12時00分〜12時59分の毎分起動になってしまうミスはありがちである。しかも排他処理をサボっていたりすると、プロセス終了前に次のプロセスが起動してしまい、数十個のプロセスが実行中になり、負荷が高くなってしまうのもありがちである。

注意点: % のエスケープ
上記で
0 18 3 * [ `date +\%Y` -eq 2017 ] && command
と書いたが、crontab データ上では % は改行を表すので、"date +%Y" は "date +\%Y" とエスケープする必要がある。

余談: Azure の crontab 定義
マイクロソフト Azure の WebJob で crontab 定義ができるのだが、そこでは
秒 分 時 日 月 曜日 コマンド
と先頭に「秒」が追加されている。

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

cron は中小規模のシステムでは全く問題ないものの、大規模な商用システムでは上記のような欠点があるために、JP1・Senju(千手)・Hinemos・Tivoli などのジョブ管理ツールを使うことが多い。例えば、
0時からバッチA→バッチB→バッチC を実行し、3時からバッチD→バッチE を実行し、バッチC とバッチE の完了を待ってバッチFを実行するときにバッチBが異常終了した際、夜間監視を行なっているオペレータがバッチB以降を再実行する
といった運用があったとして、cron なりコマンドラインなりで完結させるのはなかなかに難しい。上記のジョブ管理ツールは GUI 画面を提供し、どの箇所でエラーになったのか・エラー内容は何かをわかりやすく表示し、ボタンひとつで再実行できたりする。
>> OSオンラインマニュアル(man) FreeBSD crontab(1)
>> OSオンラインマニュアル(man) Solaris10 crontab(1)
>> OSオンラインマニュアル(man) Linux crontab(5)
>> OSオンラインマニュアル(man) Linux crontab(1)

crypt 暗号化・復号化ツール

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

csh Cシェル

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

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

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

ctags 

cu モデムのチェック。

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

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

cut コマンドは、各行から「n 文字目から m 文字目」「n 番目から m 番目からのカラム」というようなルールで文字列を切り出す。空白 (スペース)・タブ・カンマなど、区切り文字を指定することもできる。cut コマンドは古くから存在するため (SystemIII で登場)、あらゆる UNIX/Linux 系 OS で使用可能である。


バイト数で指定
-b[num1]-[num2] num1 バイト目からnum2 バイト目までを切り出す。先頭は 0 ではなく 1 から始まる。
% 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 文字目までを切り出す。先頭は 0 ではなく 1 から始まる。
バイト単位で切り出す -b オプションと同様の動作をするが、正しくロケールを認識する Solaris などでは日本語としての文字数を指定できるが、Linux 系 OS では -c を指定しても -b と同じ扱い (バイト単位) になるようだ。
% 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 フィールド番号 指定したフィールドを出力する。先頭は 0 ではなく 1 から始まる。
% 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番目以降のフィールドを表示
デフォルトのフィールド区切りは TAB であるが、-d オプションを使うことでカンマや空白・スペース等に変更できる。
% command | cut -d',' -f 2,3
abc def
⇒ カンマを区切りとして、2番目と 3番目のフィールドを表示
% command | cut -d' ' -f 2,3
⇒ 空白・スペース区切りとして、2番目と 3番目のフィールドを表示
abc def

区切り文字 (デリミタ) を指定
cut コマンドの標準の区切り文字 (セパレータ) はタブ (TAB) であるが、-d オプションを使うと区切り文字を空白 (スペース) やカンマなどに変更することができる。-d オプションを使う場合は -f オプションを同時に指定しないと意味がないことに注意。
% cat file.txt
abc,def,ghi,,jkl
% cut -d , -f 2,3 < file.txt
def,ghi
⇒ カンマ区切りとみなして 2番目と 3番目のフィールドを表示
% command | cut -d" " -f 5-8
⇒ スペース区切りとみなして 5〜8番目のフィールドを表示

-d オプションでは複数の文字を指定することはできないため、「カンマと空白のいずれかを区切り文字とする」ということはできない。また、連続した区切り文字を 1つの区切り文字として扱うこともできない。

例えば ls コマンドのように
-rw-rw-r--  1 68user 68user      733  1月 13 15:35 2017 file1
-rw-rw-r--  1 68user 68user      318  1月 13 15:27 2017 file2
drwxrwxr-x  2 68user 68user     4096  3月 28 17:11 2017 dir
といった連続空白がある場合は、事前に tr や sed などで、カンマや連続空白を 1つの空白にまとめるなどの工夫が必要である。
% ls -l | tr -s ' ' | cut -d ' ' -f 5,9
⇒ 連続空白を 1つの空白にまとめた上で、5番目と9番目のフィールド (ファイルサイズとファイル名) を表示
% command | sed 's/[ \t][ \t]*/ /g' | cut -d ' ' -f 5,9
⇒ タブとスペース混在の場合は sed を使うとよい。

-w オプションによる区切り文字指定【2017-11-06 追加】
FreeBSD では 9.2-RELEASE より -w オプションが追加された。-w オプションを使うと区切り文字は「タブまたはスペース」となり、なおかつ連続するタブ・スペースは 1つのスペースとして扱われるため、上記の例は
% ls -l | cut -w -f 5,9
とすっきり書ける。

関連コマンド
さらに凝ったことをしたい場合は awk コマンドを使うとよい。
>> OSオンラインマニュアル(man) Solaris10 cut(1)
>> OSオンラインマニュアル(man) FreeBSD cut(1)
>> OSオンラインマニュアル(man) Linux cut(1)

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");
 }

コミット (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 で指定が可能である。

もし 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 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 は一人だけで使ってもそれなりに便利であるが、複数人による開発でこそ実力を発揮する。

サンプルは基礎編に引続き 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 のマニュアルでは 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
その理由は chmod の setgid の項を参照してほしい。

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 コマンドでがんばって補完の定義をしよう。

ヘルプ
全体のオプションを表示
% 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 自体の説明は、チュートリアル編を参照のこと。

世の中には驚くほど後進的なプロジェクトがたくさん存在するものである。
  • ソースのマスタがない
  • 開発環境と商用環境でソースに差違がある (マスタもないので、どちらが正しいかわからない)
  • 過去のソースが保存されていない (潜在バグが発覚したとき、このバグはいつから存在したのか答えられない)
  • 誰が修正したのかわからない
  • 商用環境などへのリリース作業は修正したファイルを手作業で拾いだし、ファイルをひとつずつ 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 のモジュールをコピーまたはブランチを作成する。

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

UNIX/Linux の date コマンドは、現在の日付・日時を表示したり、指定のフォーマットで年月日・時分秒・曜日・タイムゾーンなどを表示するコマンドである。前日・翌日・先月・翌月や、N日後などの時刻計算を行うこともできる。また、root であれば現在時刻を設定することもできる。


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 %H:%M:%S"
1997/02/25 06:04:41
フォーマットの書式は以下の通り。より詳しい書式は、strftime(3) を参照してほしい。
%Y 年 (4桁表示)
%y 年 (2桁表示)
%m 月 (2桁表示=ゼロパディング)
%d 日 (2桁表示=ゼロパディング)
%e 日 (ゼロパディングなし)
%h 月 (英語表示 Jan,Feb...)
%H 時 (2桁表示=ゼロパディング)
%M 分 (2桁表示=ゼロパディング)
%S 秒 (2桁表示=ゼロパディング)
%s UNIX時間 (epoch)。1970/01/01 00:00:00 からの経過秒数
% date +%s
1490278214
%n 改行
%N ナノ秒 (000000000〜999999999。ゼロパディング)
ミリ秒・マイクロ秒が必要な場合は、桁を削るとよい。GNU date のみ。
% date "+%H:%M:%S.%N"
20:19:51.001562824
→ ナノ秒
% date "+%H:%M:%S.%N" | cut -c1-15
20:19:51.001562
→ マイクロ秒
% date "+%H:%M:%S.%N" | cut -c1-12
20:19:51.001
→ ミリ秒
%T 24時間表記の時刻 (%H:%M:%S と同じ)
%t タブ
%Z タイムゾーン
%% 「%」自体

なお、% 以外は好きに書いてよいので、
% date "+時刻は[[%Y/abc%mdef/%d]]です"
時刻は[[2017/abc03def/23]]です
と書いてもよい。

GNU date の場合、下記のようにゼロパディングを抑止できる。
% date '+%Y/%_m/%_d'
2017/ 3/23
→ アンダーバー指定で空白詰め
% date '+%Y/%-m/%-d'
2017/3/23
→ ハイフン指定でパディングしない

UNIX時間 (epoch) を日時に変換
BSD
% date -j -f "%s" 1490278214
2017年 3月23日 木曜日 23時10分14秒 JST
% date -r 1490278214
2017年 3月 23日 木曜日 23:10:14 JST
GNU date では先頭に "@" を付けることで、UNIX 時間とみなしてくれる。
% date -d @1490278214
2017年 3月 23日 木曜日 23:10:14 JST

BSD 系の日付・時刻の計算 (前日・翌日・n時間後・n日後・nヵ月後)
FreeBSD・NetBSD など、BSD 系において 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ヵ月前の時刻を表示)
% date -v-1d (前日の時刻を表示)
今から 1年後の 2日前の時刻は、-v を複数回指定して
% date -v+1y -v-2d
とする。

Linux 系の日付・時刻の計算 (前日・翌日・n時間後・n日後・nヵ月後)
Linux 系の場合、-d または --date オプションを使う。
未来
date -d '1 year' 1年後(翌年)
date --date '1 year' 1年後(翌年)
→ -d でも --date でも同じ
date --date '1 month' 1ヶ月後(翌月)
date --date '1 day' 1日後(翌日)
date --date '1 hour' 1時間後
date --date '1 minute' 1分後
date --date '1 sec' 1秒後
過去の場合は、マイナスを付けるか、末尾に ago を付ける。
date --date '-1 year' 1年前(前年)
date --date '1 year ago' 1年前(前年)
→ "-1 year" の代わりに "1 year ago" でもよい。
date --date '-1 month' 1ヶ月前(先月)
date --date '-1 day' 1日前(前日)
date --date '-1 hour' 1時間前
date --date '-1 minute' 1分前
date --date '-1 sec' 1秒前
date --date '-1 sec' 1秒前
今から 1年後の 2日前の時刻は、--date の後の引数に全部押し込む。ただし ago の位置が非常にわかりづらいので、"1 year -2 day" の書き方がよいのではないかと思う次第である。
% date --date '2 day ago 1 year'
% date --date '1 year 2 day ago'
% date --date '1 year -2 day'
とする。

時刻のパースと計算
"2017/03/23" などの、年月日時分秒などの文字列をパースさせる方法を説明する。何のためにパースさせるかというと、異なるフォーマットで表示するか、1ヶ月後などの日付計算をするためなので、その方法もあわせて提示する。

BSD date の場合。-f にてフォーマットを指定する。
% date -j -f "%Y/%m/%d" 2017/03/23
2017年 3月23日 木曜日 23時38分54秒 JST
% date -j -f "%Y/%m/%d %H:%M:%S" "2017/03/23 01:02:03"
2017年 3月23日 木曜日 01時02分03秒 JST
% date -j -v+1y -f "%Y/%m/%d" 2017/03/23 +%Y%m%d
→ 2017/03/23 の 1年後 (-v+1y) を、%Y%m%d (YYYYMMMDD) で表示

GNU date では、-d または --date オプションに、日付っぽい文字列を渡せばよい。
% date -d '2017/03/23'
2017年 3月 23日 木曜日 00:00:00 JST
% date -d "2017/03/23 01:02:03"
2017年 3月 23日 木曜日 01:02:03 JST
さらに日付計算も -d または --date にまとめて書けばよいので、下記のように簡単に書ける。
% date -d "2017/03/23 01:02:03 2 year"
2019年 3月 23日 金曜日 01:02:03 JST
→ 2年後 (2 year) を表示
% date -d "2017/03/23 01:02:03 1 year" "+%Y年%m月%d日(%a) %H時%M分%S秒"
2018年03月23日(金) 01時02分03秒
→ それを指定のフォーマットで表示
GNU date の場合、簡単なのはよいのだが、任意のフォーマットでのパースができないようだ。例えば RFC 3339 形式である "2001-02-03T04:05:06+09:00" は解釈できない。BSD date のように -f オプションでフォーマットを指定できないようだ。よって、sed 等でタイムゾーン部分を削るなどの対応が必要となる。

-v オプションも --date オプションも使えない場合
例えば Solaris の date では -v オプションも --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 を使うとよい。
>> OSオンラインマニュアル(man) Solaris10 date(1)
>> OSオンラインマニュアル(man) FreeBSD date(1)
>> OSオンラインマニュアル(man) Linux date(1)

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

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

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 コマンドを使ってもよい。

主要オプション一覧
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 にしたらしい。
>> OSオンラインマニュアル(man) FreeBSD dd(1)
>> OSオンラインマニュアル(man) Solaris10 dd(1M)
>> OSオンラインマニュアル(man) Linux dd(1)

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 を設定しておく手もある。

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
とすることで、使用率を表示することができる。
>> OSオンラインマニュアル(man) FreeBSD df(1)
>> OSオンラインマニュアル(man) Solaris10 df(1M)
>> OSオンラインマニュアル(man) Linux df(1)

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

diff コマンドは、2つのテキストファイルの違い (差分) を表示するコマンドである。ファイル内容が一致しているかの確認も可能。ディレクトリを再帰的にたどり、複数のファイルを一括して差分表示することもできる。

基本的な使い方
2つのファイルの違いを表示したいとき、
% diff file1 file2
1c1
< modify
---
> modify2
3d2
< remove
5a5
> add
とすると、file1 と file2 の相違点を表示する。上記の例では、
  • file1 の modify が、file2 では modify2 に変わった
  • file2 にあった remove が、file2 では削除された
  • file1 になかった add が、file2 で追加された
ということを表している。"<" や ">" の方向がわかりづらい場合、diff -u を使うと "+" "-" になるので、こちらの方が直感的にわかりやすいのではないだろうか。
% diff -u file1 file2
--- file1 2017-03-21 03:43:42.361439427 +0000
+++ file2 2017-03-21 03:43:54.937869712 +0000
@@ -1,5 +1,5 @@
-modify
+modify2
a
-remove
c
d
+add

システムの設定ファイルをいじる場合は、最初に
% cp rc.conf rc.conf.org
などとオリジナルを保存し、適宜
% diff rc.conf.org rc.conf
として差分を取ることで、修正点を確認するようにしておくとよいだろう (バージョン管理しておくのが一番よい)。ちなみに "diff [新ファイル] [旧ファイル]" ではなく、"diff [旧ファイル] [新ファイル]" とするのが一般的。

パイプを使って標準入力と比較
ファイル名として - を指定すると標準入力と比較する。例えば
% command | diff - file
は command の出力と file の内容を比較する。

コマンドの出力結果同士の差分
コマンドの出力結果同士の差分を見たい場合は、bash であれば
% diff <(cmd1 a.txt) <(cmd2 b.txt)
とする。括弧の中は
% diff <(cmd1 a.txt | cmd2 | cmd3) <(cmd4 b.txt | cmd5 | cmd6)
のようにパイプでもなんでも使える。

bash 以外の sh 系シェルであれば、
% cmd1 | ( cmd2 | diff /dev/fd/3 -) 3<&0
とすればよい。

ディレクトリの差分
引数の両方にディレクトリ名を指定した場合は、2つのディレクトリ以下に存在するファイルの差分を表示する。
% diff 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 の差分しか表示しない。

特定のファイル名を除外したい場合、-x または --exclude オプションを使い、
% diff -r --exclude="*.png" dir1/ dir2/
→ *.png を除外
% diff -r --exclude=".svn" --exclude=".git" --exclude="*.log" dir1/ dir2/
→ .svn、.git、*.log を除外。exclude を複数指定してもよい。
などと除外することができる。

パッチ作成
パッチを作成するときにも 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 または --context オプションを付ける。
% 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 オプションを付けると 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
context diff 形式の出力をする。"-c 5"、"--context=5" で、差異の前後 5行を表示する。
-u または --unified
unified diff 形式の出力をする。"-u 5"、"--unified=5" で、差異の前後 5行を表示する。
-e または --ed
ed diff 形式の出力をする。普通は使わない。
-r または --recursive
ディレクトリを比較したとき、その下のサブディレクトリを再帰的にたどっていく。
-a または --text
テキストファイルとして比較する。
-b または --ignore-space-change
空白 (スペース)・タブの数の違いを無視する。
-w または --ignore-all-space
空白 (スペース)・タブの有無を完全に無視する。"abc" と "a b c" が同じとなる。
-i または --ignore-case
大文字・小文字の違いを無視する。
-B または --ignore-blank-lines
空行のある・なしの違いを無視する。
--strip-trailing-cr
改行コード CR を削除する。LF と CR+LF が混在したまま比較した場合に使う。改行コードは一般的には UNIX では LF、DOS/Windows では CR+LF、Mac では CR。このオプションでは Mac 式の CR な改行コードはうまく扱えない。あきらめて tr・sed・perl などで改行コードを変換しよう。
-y または --side-by-side
2つのファイルを、横に並べて表示する。十分な端末の横幅がないと見にくくなってしまう。-W オプションで横幅を指定できる。
-W または --width
-y オプションを付けたときの、横幅を指定。
% diff -y -W60 file1 file2
⇒ 差分を横に並べて表示。横幅は60文字。
-q または --brief
ファイルが異なる場合、差分を表示せず、異なる旨を表示する。
% diff -q a.txt b.txt
Files a.txt and b.txt differ
→ あるいは「ファイル a.txt と b.txt は異なります」
-s または --report-identical-files
ファイルが同じな場合、その旨表示する。
% diff -s a.txt a.same.txt
Files a.txt and a.same.txt are identical
→ あるいは「ファイル a.txt と a.same.txt は同一です」
-q (--brief) と -s (--report-identical-files) を同時に使うと、全ファイルについて、同じか異なるかを表示してくれる。
-I または --ignore-matching-lines=[正規表現]
正規表現にマッチした行は無視する (差分としては除外する)。
% diff --ignore-matching-lines="last-modified: [-0-9/ :]+" out-20170321.txt out-20170322.txt
→ last-modified: YYYY/MM/DD HH:MM:SS という部分は毎回変わるので、その行は無視する。
-x [ファイルパターン] または --exclude=[ファイルパターン]
特定のファイル・ディレクトリパターンは無視する。ディレクトリの比較時、一括して除外したいファイルを指定する。
% diff -r --exclude="*.png" dir1/ dir2/
→ *.png を除外
% diff -r --exclude=".svn" --exclude=".git" --exclude="*.log" dir1/ dir2/
→ .svn、.git、*.log を除外。exclude を複数指定してもよい。
% diff -r --exclude="*.[ao]" dir1/ dir2/
→ *.a と *.o を除外

バイナリファイルのパッチ生成には、xdelta や bsdiff を使う。
>> OSオンラインマニュアル(man) Linux diff(1)
>> OSオンラインマニュアル(man) FreeBSD diff(1)
>> OSオンラインマニュアル(man) Solaris10 diff(1)

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

dig 名前解決を行う

http://X68000.q-e-d.net/~68user/net/resolver-1.html を参照。

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

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

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

OS のブート時のメッセージを、ブート後に参照したい場合に使う。また、ディスクが一杯でファイルを書き込めなかった、などのエラーメッセージも表示される。しかし rc.local などで表示されるメッセージは表示されない。
>> OSオンラインマニュアル(man) FreeBSD dmesg(8)
>> OSオンラインマニュアル(man) Linux dmesg(8)

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ギガバイト単位
-s 指定ディレクトリのサブディレクトリの使用量を表示しない。
du / だと /usr、/bin、/etc、さらに /usr/bin や /usr/local/bin などの容量も表示するが、-s を指定すると
% du -s /
/ 6563241
と、全ての容量を合計した値が表示される。
% du -s /*
とすると、サブディレクトリを表示せずに / 以下の各ディレクトリのサイズを表示する。
-c 全てのファイル・ディレクトリの容量の合計を表示 (FreeBSD 2.2.7-RELEASE 以降)
>> OSオンラインマニュアル(man) Linux du(1)
>> OSオンラインマニュアル(man) FreeBSD du(1)
>> OSオンラインマニュアル(man) Solaris10 du(1B)

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

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

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

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

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 コマンドを使うこと。

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

echo は xargs と組み合わせても便利である。

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

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

elvis 日本語を表示できる vi

emacs 高性能エディタ

とっても有名なエディタ。詳しい説明は mule の項を参照。

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

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

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

>> OSオンラインマニュアル(man) FreeBSD env(1)
>> OSオンラインマニュアル(man) Solaris10 env(1)
>> OSオンラインマニュアル(man) Linux env(1)

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

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

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

ethereal パケット監視ツール

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

使用例は http://X68000.q-e-d.net/~68user/net/resolver-1.html を参照。

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 に変換

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 の内部コマンド。

export コマンドは、環境変数を設定・定義・更新する sh・bash の内部コマンドである。csh・tcsh では export コマンドではなく setenv コマンドを使う。

環境変数の設定方法
sh・bash にて環境変数を設定するには、まずシェル変数をセットし、その後に export コマンドを実行するやり方が一般的である。
% FOO="BAR"
% export FOO
セミコロンでつなげて一行で書くのもよくある書き方である。
% FOO="BAR"; export FOO

しかしながら、export コマンドというのは、「この変数を環境変数として外部公開するという印を付ける」という意味であるため、最初に export でマークして、後から変数設定を行なっても全く問題ない。
% export FOO
% FOO="BAR"

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

PATH の更新方法
export コマンドを使って環境変数 PATH を更新する方法を以下に示す。
% PATH="${PATH}:/usr/local/sbin"
% export PATH
→ PATH 末尾に /usr/local/sbin を追加。
% PATH="${PATH}:${HOME}/bin"
% export PATH
→ PATH 末尾に $HOME/bin を追加。

環境変数 PATH 自体の説明やリスクは下記を参照してほしい。

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

csh・tcsh で環境変数を設定するには setnev コマンドを使用する。

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

exit コマンドは、現在実行中のシェルを終了するコマンドである。sh・bash・csh・tcsh などすべてのシェルで使うことができる。


基本的な使い方
コンソールや ssh 経由等でログインして、sh・bash・csh・tcsh などのシェルを実行中のときに、
% exit
と exit コマンドを実行することでそのシェルを終了することができる。ログインシェルであった場合は、ログアウトすることになる。

下記のようにシェルをいくつも起動していた場合、現在実行中のシェル (最後に起動したシェル) を終了し、その直前のシェルに戻ることになる。
(ssh 等でログイン)
% tcsh
% bash
$ csh
% exit → csh を終了
$ exit → bash を終了
% exit → tcsh を終了
% exit → ログインシェルを終了 (=ログアウト)

サスペンド中のプロセスがある場合
もし
% sleep 1000
(Ctrl-z でサスペンド)
[1]+ Stopped sleep 1000
などと Ctrl-Z や stop コマンドなどでサスペンド (中断) したジョブがある場合に exit コマンドを実行しようとすると、
% exit
There are suspended jobs.

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

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

Ctrl-d でのシェルの終了
sh・bash・csh・tcsh いずれも、プロンプトで何も入力していない状態で Ctrl-d を入力すると、シェルを抜けることができる。しかしながら bash・tcsh では、行途中での Ctrl-d は補完機能を持つために、誤ってシェルを終了する事故が起こりやすい。
% abc(Ctrl-d)
→ ここでの Ctrl-d はコマンド補完なのに
% (Ctrl-d)
→ これだと exit してしまう!

Ctrl-d によるシェルの終了を抑止するには、csh・tcsh ではシェル変数 ignoreeof、bash では IGNOREEOF を設定するとよい。

シェルスクリプトでの exit コマンド
シェルスクリプト内で exit コマンドを記述すると、そこでスクリプトの実行をやめて終了する。
#!/bin/sh
...
if [ ... ]; then
echo "Error occurred."
exit
fi

一般的には、正常終了時は 0 を、異常終了時は 1 を返すべきであるので、
#!/bin/sh
...
if [ ... ]; then
echo "Error occurred."
exit 1
fi
exit 0
と書くのが望ましい。なお、単に exit と書くと、直前に実行したコマンドの終了ステータスを返して終了してしまうので、シェルスクリプトにおいては exit 0 などと値を明記した方がよいと思われる。詳しくは下記項目を参照のこと。

sh・bash シェルスクリプトの while 内での exit
下記のように while ループ内で exit した場合、シェルスクリプトは終了せず、while do〜done の後の後続処理部分も処理が続いてしまう。なぜならば while ループはサブシェルで実行されるため、exit はサブシェルが終了するだけであり、親のシェルの処理は続行してしまうからである。
#!/bin/sh
cat data.txt | while read line; do
if [ "${line}" = "BAD LINE" ]; then
exit 1
fi
done
... 後続処理 ...

このような場合は、下記のようにループ終了後に終了ステータスを確認し、while ループ内で異常が発生したかをチェックするとよい。
#!/bin/sh
cat data.txt | while read line; do
if [ "${line}" = "BAD LINE" ]; then
exit 99
fi
done
if [ $? = 99 ]; then
exit 1
fi
... 後続処理 ...

関連コマンド
現在のシェルを終了するのではなく、中断して一時的に親のシェルに戻りたい場合は、suspend コマンドを使うとよい。

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

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

fold や TeX の文章中などは、タブを認識してくれないので、事前にタブをスペースに変換しておく必要がある。expand コマンドの代わりに、emacs や mule の M-x untabify を使ってもいい。
>> OSオンラインマニュアル(man) Linux expand(1)
>> OSオンラインマニュアル(man) Solaris10 expand(1)
>> OSオンラインマニュアル(man) FreeBSD expand(1)

f77 Fortranコンパイラ

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

FreeBSD では /usr/games/ の下にインストールされるので注意。
>> OSオンラインマニュアル(man) Linux factor(6)
>> OSオンラインマニュアル(man) Linux factor(1)
>> OSオンラインマニュアル(man) Solaris10 factor(1)

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 秒たってもダウンロードが終了しなければあきらめる。
>> OSオンラインマニュアル(man) FreeBSD fetch(1)

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

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

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

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

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

なお、fgrep は Fixed GREP の略である (Fast GREP ではない)。固定文字列の検索用、ということ。
>> OSオンラインマニュアル(man) Linux fgrep(1)
>> OSオンラインマニュアル(man) Solaris10 fgrep(1)

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 で。

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

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

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

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

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

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

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

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

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);

find ファイル名・タイムスタンプ・ファイルサイズなどを元に、ファイル・ディレクトリを検索する。

UNIX/Linux の find コマンドは、ファイル名・タイムスタンプ・ファイルサイズ・オーナー・グループ・ファイルタイプなどを元に、ファイルやディレクトリを検索するコマンドである。AND・OR の組み合わせや正規表現が使えたり、検索だけではなくコマンドの実行も可能など、非常に強力なコマンドである。

目次:

find コマンドの基本的な使い方
find コマンドの基本的な使い方は、下記のとおりである。
% find 検索開始ディレクトリ 検索条件 アクション
find は「検索開始ディレクトリ」以下のディレクトリを再帰的に検索する。よって、
% find / ...
は、そのマシン内の全ファイルを対象に検索することになる。

FreeBSD・Linux など一部の find では、
% find /usr
と、検索開始ディレクトリのみを指定すると、コマンドとして -print が指定されたものとして動作する。また、Linux などの GNU 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 以下の全ファイルを表示
find は「検索開始ディレクトリ」以下のディレクトリを再帰的に検索する。よって、
% find / ...
は、そのマシン内の全ファイルを対象に検索することになる。

なお、カレントディレクトリにディレクトリ dir/ が存在する場合、
% find . ./dir
とすると、./dir 以下が 2重でリストアップされることに注意。

検索条件オプション ファイル名
-name file
検索するファイル名・ディレクトリ名を指定する。指定するファイル名は部分一致ではなく完全一致であることに注意しよう。
% find . -name foo.txt -print
→ 「foo.txt」というファイルまたはディレクトリを検索する。「foo.txt.bak」はヒットしない。
% find . -name mydir -print
→ 「mydir」というファイルまたはディレクトリを検索する。「mydir2」はヒットしない。
ワイルドカードとして *・?・[・] を使用することが可能だが、その場合は "" などで囲んだり、エスケープしよう。
% find . -name "*abc*"
→ 名前のどこかに "abc" を含むファイルまたはディレクトリを検索する。
% find . -name \*abc\*
→ \ でエスケープしてもよい。
ワイルドカードでは足りない複雑な条件の場合、より強力な -regex で正規表現で指定するとよい。

-name は、「そのエントリのみ」が検索対象であることに注意。カレントディレクトリ以下に
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 と同じ。

検索条件オプション タイムスタンプ・日付
タイムスタンプや日付・日時をキーとしてファイル・ディレクトリを検索する方法を説明する。伝統的な UNIX でも *BSD でも Linux でも使えるのは -mtime や -newer ではあるが、なにしろ大変わかりづらい。-mtime オプションなどは仕様すら異なる。FreeBSD や Linux などの GNU ベースの find 限定ではあるが、おすすめは -newermt オプションで、-newermt '2017-05-26' や -newermt '2017-05-26 19:01:12' などとわかりやすく日付や時刻を指定することができる。
-mtime [+-]n
mtime オプションを使うと、n日前に修正されたファイルを検索することができる。日数にプラスマイナスをつけることで、N日以前・N日以後・N日より前、などの条件をつけることができる。驚くことに、BSD の find と GNU の find で、mtime +N の意味が異なるようだ。要注意である。
-mtime 1 1日前 (24時間前〜現在) に修正されたファイル
-mtime 2 2日前 (48時間前〜24時間前) に修正されたファイル
(BSD find)-mtime +0 現在より前に修正されたファイル
(BSD find)-mtime +1 1日前 (24時間前) より前に修正されたファイル
(GNU find)-mtime +0 1日前 (24時間前) より前に修正されたファイル
(GNU find)-mtime +1 2日前 (48時間前) より前に修正されたファイル
-mtime -0 現在より後に修正されたファイル
-mtime -1 1日後 (24時間後より後) に修正されたファイル

UNIXのタイムスタンプ全般についてはタイムスタンプの項を参照。
-atime [+-]n
n日前にアクセスされたファイル。それ以外は mtime と同じ。
-ctime [+-]n
n日前にファイルステータスが変更されたファイル。それ以外は mtime と同じ。
-newer file
ファイル file よりタイムスタンプが新しいファイル・ディレクトリを検索。タイムスタンプ比較用ファイルをあらかじめ作成し、touch コマンドを使ってタイムスタンプを変更し、そのファイルと比較するとよい。"newer" なので、比較対象ファイルより「新しいもの」を検索することに
注意 (同じタイムスタンプはマッチしない)。

逆に、「〜より古い」という条件で検索したい場合は、条件の否定を使う。
% find . \! -newer file -print
-newermt 'YYYY-MM-DD' または -newermt 'YYYY-MM-DD HH:MM:SS'
指定した日付・時刻よりも新しいファイル・ディレクトリを検索する。'YYYY-MM-DD' と日付のみを指定した場合は、'YYYY-MM-DD 00:00:00' と同じとなる。"newer" なので、この日付・時刻より「新しいもの」を検索することに注意 (同じタイムスタンプはマッチしない)。

% find . -newermt '2017-05-26'
→ 最終更新時刻が 2017-05-26 00:00:00 より新しいファイルを検索 (同じタイムスタンプは含まない)
% find . -newermt '2017-05-26 11:22:33'
→ 時分秒まで指定
% find . \! -newermt '2017-05-26'
→ 最終更新時刻が 2017-05-26 00:00:00 以前のもの (同じタイムスタンプも含む)
% find . -newermt '2017-05-26' \! -newermt '2017-05-28'
→ 最終更新時刻が 2017-05-26 00:00:00 より新しく、2017-05-28 00:00:00 以前のもの
-newerXY [指定文字列]
上記ではよく使われると思われる -newermt オプションを紹介したが、実際は -newerXY というオプションの一例にすぎない。-newerXY とは何かを言葉で説明するとまず伝わらないと思うので、下記の -newerXY の全パターンを参考にしてほしい。
-newerat [日付]
最終アクセス時刻 (atime) が指定日付より新しいファイル
-newerct [日付]
最終ステータス変更時刻 (ctime) が指定日付より新しいファイル
-newermt [日付]
最終変更時刻 (mtime) が指定日付より新しいファイル
-newerBt [日付]
ファイル作成時刻 (birthtime) が指定日付より新しいファイル
-newerac a.txt
最終アクセス時刻 (atime) が a.txt の最終ステータス変更時刻 (ctime) より新しいファイル
-neweram a.txt
最終アクセス時刻 (atime) が a.txt の最終変更時刻 (mtime) より新しいファイル
-neweraB a.txt
最終アクセス時刻 (atime) が a.txt のファイル作成時刻 (birthtime) より新しいファイル
-newerca a.txt
最終ステータス変更時刻 (ctime) が a.txt の最終アクセス時刻 (atime) より新しいファイル
-newercm a.txt
最終ステータス変更時刻 (ctime) が a.txt の最終変更時刻 (mtime) より新しいファイル
-newercB a.txt
最終ステータス変更時刻 (ctime) が a.txt のファイル作成時刻 (birthtime) より新しいファイル
-newerma a.txt
最終変更時刻 (mtime) が a.txt の最終アクセス時刻 (atime) より新しいファイル
-newermc a.txt
最終変更時刻 (mtime) が a.txt の最終ステータス時刻 (ctime) より新しいファイル
-newermB a.txt
最終変更時刻 (mtime) が a.txt のファイル作成時刻 (birthtime) より新しいファイル
-newerBa a.txt
ファイル作成時刻 (birthtime) が a.txt の最終アクセス時刻 (atime) より新しいファイル
-newerBc a.txt
ファイル作成時刻 (birthtime) が a.txt の最終ステータス時刻 (ctime) より新しいファイル
-newerBm a.txt
ファイル作成時刻 (birthtime) が a.txt の最終変更時刻 (mtime) より新しいファイル
タイムスタンプの種類については、下記を参考にしてほしい。ただし、ファイル作成時刻 (B:birthtime) を使えるのは 2017/05 時点では FreeBSD 5.0-RELEASE 以降など、一部の環境と思われる。
検索条件オプション ユーザ・グループ
-user ユーザ名またはUID
指定のユーザが所有するファイル・ディレクトリ等
-group グループ名またはGID
指定のグループが所有するファイル・ディレクトリ等
-nouser
/etc/passwd に載っていない UID が所有するファイル・ディレクトリ等
-nogroup
/etc/group に載っていない GID が所有するファイル・ディレクトリ等
-nouser と -nogroup は、削除済のユーザ・グループが所有していたファイル・ディレクトリが残っていないかの確認に使う。
検索条件オプション 階層系
-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"
と同じである。
検索条件オプション ファイルサイズ
-size [+-]n[ckMG]
ブロックサイズまたはファイルサイズで検索。「-size 100」だとブロックサイズとみなし、「-size 100c」などと末尾に c をつけるとファイルサイズとみなす。サイズの前に「+」「-」を付けることで、N以上・N以下を指定できる。
% 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 で参照できる。

また、GNU find では「-size 100k」「-size 100M」「-size 100G」とすることで、キロバイト・メガバイト・ギガバイトの指定ができる (1k=1024バイト、1M=1,048,576バイト、1G=1,073,741,824バイト)。

+ - について、以上なのか超なのか、以下なのか未満なのかは未調査。なぜか BSD も GNU も、find のマニュアルに + - について言及がない。
-empty
空のファイル、空のディレクトリの場合。具体的には
  • 「ファイルで、そのサイズがゼロ」
  • 「ディレクトリで、その下にファイル・ディレクトリ等がない」
のいずれかである。
検索条件オプション パーミッション 【2017-06-01 追加】
パーミッションで検索する場合、-perm オプションを使う。指定方法が 3通りあるので、分けて説明する。
▷ -perm [パーミッション文字列]
絶対指定。[パーミッション文字列] に完全に一致するファイル・ディレクトリを検索する。

[パーミッション文字列] には 644 といった 8進数指定や、u=rw,g=r,o=r といったシンボルでの指定ができる。なお、u はオーナー、g はグループ、o はその他、である。a を使うとオーナー・グループ・その他をまとめて指定できる。

例えば、下記 3つはすべて同じ意味である。
% find . -perm 644 -ls
% find . -perm u=rw,g=r,o=r -ls
% find . -perm a=r,u+w -ls

以下の 8進数指定とそれに続くシンボル指定は、それぞれ同じ意味である。
% find . -perm 000 -ls
% find . -perm u=,g=,o= -ls
% find . -perm 644 -ls
% find . -perm u=rw,g=r,o=r -ls
% find . -perm 666 -ls
% find . -perm a=rw -ls
% find . -perm 755 -ls
% find . -perm u=rwx,g=rx,o=rx -ls
% find . -perm 777 -ls
% find . -perm a=rwx -ls
% find . -perm 4755 -ls
% find . -perm u=rwxs,g=rx,o=rx -ls
% find . -perm 2755 -ls
% find . -perm u=rwx,g=rxs,o=rx -ls
% find . -perm 1755 -ls
% find . -perm u=rwx,g=rx,o=rxt -ls

▷ -perm -[パーミッション文字列]
先頭にハイフンをつけることで AND 検索となる。パーミッション文字列で指定した全てのビットが立っているファイル・ディレクトリを検索する。-perm 644 形式とは異なり、指定していないビットが立っていても検索対象となる。

例えば下記は、「グループ」に書き込み権限があり、なおかつ (AND) 「その他」に書き込み権限があるファイル・ディレクトリを検索する。

また、022 以外のビットが立っているか否かは無関係なので、777 (rwxrwxrwx) や 666 (rw-rw-rw-) にもマッチする。AND 検索なので、707 (rwx---rwx) や 660 (rwxrwx---) にはマッチしない。
% find . -perm -022
% find . -perm -g=w,o=w

▷ -perm +[パーミッション文字列] または -perm /[パーミッション文字列]
先頭に + や / を付けることで OR検索となる。パーミッション文字列で指定したのビットがいずれかが立っているファイル・ディレクトリを検索する。-perm 644 形式とは異なり、指定していないビットが立っていても検索対象となる。

例えば下記は、「グループ」に書き込み権限があるか、または (OR) 「その他」に書き込み権限があるファイル・ディレクトリを検索する。

また、022 以外のビットが立っているか否かは無関係なので、777 (rwxrwxrwx) や 666 (rw-rw-rw-) にもマッチする。OR 検索なので、707 (rwx---rwx) や 660 (rwxrwx---) にもマッチする。
% find . -perm +022 -ls
% find . -perm +g=w,o=w -ls
下記は、全ファイルから setuid または setgid または sticky bit が立っているファイルを検索するものである。
% find / -perm +7000 -ls
% find / -perm +u=s,g=s,o=t -ls

なお、-perm +[パーミッション文字列] については仕様バグがあり、-perm +u+x としたとき、-perm +111 と -perm 111 の 2パターンの解釈ができてしまう。実装上は -perm 111 となるようである。(と GNU find のマニュアルには書いてある)。

そこで GNU find では -perm + に変わり -perm / という書き方を導入した。Linux など GNU find が使える環境では -perm / を使い、それ以外では -perm + を使うとよい。書式は下記のように -perm + を -perm / に変えるだけである。
% find . -perm /022 -ls
% find . -perm /g=w,o=w -ls
検索条件オプション ファイルタイプ
-type [ファイルタイプ] ファイルの種類
-type オプションに続けて以下のようなファイルタイプを指定することで、ファイルのみ・ディレクトリのみ、などと特定のファイルタイプのみを選択できる。また、! や -not を使うことで、特定のファイルタイプを除外する。
% find . -type f
→ ファイルのみを検索する。
% find . -type d
→ ディレクトリのみを検索する。
% find . -type f or -type l
→ ファイルまたはシンボリックリンクを検索する。
% find . \! -type d
→ ディレクトリのみ除外する。

-type オプションで使用可能なファイルタイプを以下に示す。
b ブロックデバイス
c キャラクタデバイス
d ディレクトリ
f ファイル
l シンボリックリンク
p 名前付きパイプ
s ソケット (UNIX ドメインソケット)
D Door (Solaris のみ)
検索条件オプション i-node 【2017-07-04 追加】
-inum inode 番号
指定の inode のファイルまたはディレクトリ。inode は ls -i で確認できる。例えば、
% ls -l
-rw-r--r-- 1 user group 0 Jul 4 13:43 ???????????????
のように文字化けしたファイルができてしまった場合、
% ls -li
22327771 -rw-r--r-- 1 user group 0 Jul 4 13:43 ???????????????
として inode を確認した上で、下記のようにすれば削除したり、リネームしたりすることができる。
% find . -inum 22327771 -delete
→ 削除
% find . -inum 22327771 -ok mv {} abc.txt \;
→ abc.txt にリネーム

なお、コントロールコードを含むファイルは、例えば
% perl -e '$fn=pack("C*", 1..15);open(OUT, ">", $fn)'
などで作成可能である。これは 0x01〜0x0F というファイル名のファイルを生成する。

inode はファイルシステムごとの通番のような番号なので、複数のファイルシステムにまたがった場合は同じ inode が存在する可能性があることに注意。例えば、/・/usr・/home・/var という 4つのファイルシステムがマウントされている場合、
% find /usr -inum 100
であればファイルが 1つに特定できるが、
% find / -inum 100
とすると /・/usr・/home・/var それぞれの inode が 100 であるファイルが表示される可能性がある。
条件の結合・否定などのオプション (AND 条件・OR 条件・NOT) 【2017-09-06 -and・-or・-not は使えない環境があることを追記】
-a または -and オプション。-and は使えない環境もある。
検索条件を AND で結ぶ。
% find . -name abc -and -type d
⇒ abc という名前のディレクトリを検索
ただし、複数の検索条件を並べて書けば AND として扱われるので、上記コマンドは
% find . -name abc -type d
と同じ。
-o または -or オプション。-or は使えない環境もある。
検索条件を OR で結ぶ。
% find . -name abc -or -name def
⇒ abc か def という名前のファイル・ディレクトリを検索
しかしながら、
% find . -name abc -or -name def -print
のように -print などのアクションを付けると def は表示されるが、abc は表示されないので、
% find . \( -name abc -or -name def \) -print
と -or 部分を括弧で囲うようにすればよい。この理由は こちら を参照。
! または -not オプション。-not は使えない環境もある。
他の条件の前に付けて、条件を否定する。-not は一部の find でしか使えない。
% find . \! -name \*.txt -print
⇒ 拡張子が .txt で *ない* ファイル・ディレクトリ
% find . -not -newer target.txt -print
⇒ target.txt とタイムスタンプが同じか、あるいは古いファイル・ディレクトリ

-a・-o・! は POSIX で規定されているが、-and・-or・-not はそうではない。-and・-or・-not は GNU find や FreeBSD では使用可能であるものの、Solaris の find では使用できない。
アクション: ファイル名・情報表示
-print 対象ファイル名を表示する。
% find . -name \*.txt -print
./sample.txt
./dir/sample2.txt
アクションが指定されていない場合、-print が使用されるため、下記はいずれも同じ結果となる。
% find . -name \*.txt -print
% find . -name \*.txt
-ls 対象ファイルを詳しく (ls -l と同じように) 表示する。
より正確に言うと、行頭に inode と使用ブロックサイズが表示されるため、ls -lis と同じである。
-printf これは GNU find のみで使用できるオプションだが、printf(3) のような書式でファイルの情報を表示することができる。
% find . -printf "%M %TY-%Tm-%Td %TH:%TM:%TS %p\n"
-rw-rw-r-- 2017-01-11 19:54:01.6838397390 ./.config/gcloud/.metricsUUID
drwxr-xr-x 2017-01-11 19:54:02.0138390000 ./google-cloud-sdk
-rw-r--r-- 2016-12-10 06:45:43.0000000000 ./google-cloud-sdk/path.bash.inc
-rw-r--r-- 2016-12-10 06:45:43.0000000000 ./google-cloud-sdk/path.zsh.inc
→ パーミッションと、タイムスタンプと、ファイル名を表示する例
アクション: コマンド実行 【2017-06-10 -exec {} + を追加】
-exec {} ; 検索ファイルを引数としてコマンドを実行する。
-exec の後にはコマンドを指定し、{} と書いた部分はそれぞれのファイル・ディレクトリ名に置換される。そしてコマンドの終了を示すために最後に ";" で終端する。
% find dir/ -name \*.txt -exec chmod 644 {} \;
→ dir/ 以下の *.txt について chmod 644 を実行する。
";" はシェルに解釈させずに find コマンドに渡す必要があるので、上記のように \; と書くか、あるいは ";" などと書いてエスケープする必要がある。{} と \; の間にはスペースが必要であることに注意。
-exec {} + 検索ファイルを引数としてコマンドを一括実行する。
-exec {} ; は見つかったファイル・ディレクトリそれぞれについてコマンドを実行するが、-exec {} + は一括して処理を行う。
dir/file1.txt
dir/file2.txt
dir/subdir/file3.txt
が存在するとして、-exec {} ; を使って
% find dir/ -name \*.txt -exec chmod 644 {} \;
を実行すると、
% chmod 644 dir/file1.txt
% chmod 644 dir/file2.txt
% chmod 644 dir/subdir/file3.txt
が行なわれる。

一方、-exec {} + の場合は
% find dir/ -name \*.txt -exec chmod 644 {} +
とすると、
% chmod 644 dir/file1.txt dir/file2.txt dir/subdir/file3.txt
と 1回のみ実行される。
-ok コマンド実行の前に確認を行う。
-ok は -exec と同じだが、実行する際に確認を求める。
% find dir/ -name \*.txt -ok chmod 644 {} \;
"chmod 644 dir/file1.txt"?
→ y を入力すると実際に実行される。それ以外はスキップ。
以下のように -ok {} + も使える。
% find dir/ -name \*.txt -ok chmod 644 {} +

アクション: その他
-delete 対象ファイル・ディレクトリを削除する。
% find dir/ -delete
→ dir 以下 (dir も含む) の全ファイル・ディレクトリを削除する。
% find dir/ -name \*.txt -delete
→ dir 以下から、拡張子 txt のファイルを削除する。

いろいろなアクションの実行例:
アクションの例を以下に示す。
% find / -name .cshrc -print
⇒ ルートディレクトリ以下の .cshrc を検索してフルパスを表示する
% find /usr/local -name file\* -ls
⇒ /usr/local 以下の file* を検索して詳細な情報を表示する
% find . -name \*~ -exec rm {} \;
⇒ カレントディレクトリ以下の *~ をリストアップして rm コマンドで削除する。
% find . -name \*~ -print -exec rm {} \;
⇒ コマンドは複数個指定できる。
% find . -name \*~ -exec ls {} \; -exec rm {} \;
⇒ (この例はあまり意味はないが) -exec を複数個指定してもよい。

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

Howto: 複数のディレクトリを起点として検索するには
以下のように複数のディレクトリを羅列すればよい。
% find /dir1 /dir2 /dir3 ....

Howto: ファイルまたはディレクトリのみを対象とする (-type f や -type d)
ファイルのみを検索対象とするには:
% find . -type f -print
ディレクトリのみを検索対象とするには:
% find . -type d -print

Howto: 特定の拡張子のみ対象とする or 特定の拡張子を除外するには 【2017-09-06 追記】
ファイル名やディレクトリ名が *.txt か *.sh のみ対象とするには下記のように -name を -o で結べばよい
% find dir/ \( -name \*.txt -o -name \*.sh \) -print
-regex を使う方法もあるが、残念ながら汎用的ではない。GNU find では、find デフォルトの正規表現は "emacs" であり、下記のように "(" ")" "|" をエスケープすれば使える。
% find dir/ -regex '.*\.\(txt\|sh\)' -print
しかしながら BSD の find は BRE (基本正規表現) であるので、"|" には「選択 (OR)」の意味がない。よって、BSD の find では上記の例はうまく動かない。

一方、特定の拡張子を除外するには以下のように ! や -not で否定したものを並べるか、-not -regex とする。この -regex も同様に BSD の find では動作しない。
% find dir/ -not -name \*.txt -not -name \*.sh -print
% find dir/ ! -name \*.txt ! -name \*.sh -print
% find dir/ -not -regex '.*\.\(txt\|sh\)' -print

Howto: 特定のファイル名・ディレクトリ名を除外するには
ファイル名やディレクトリ名が拡張子 bak、.svn、.DS_Store であった場合は除外するには、! か -not を使用する。
% find dir/ ! -name \*.bak ! -name .svn ! -name .DS_Store -print
% find dir/ -not -name \*.bak -not -name .svn -not -name .DS_Store -print

Howto: ファイル名について大文字小文字を区別せずに検索するには
-iname オプションを使うことで、file.txt にも FILE.TXT にもマッチする。正規表現を使いたい場合は -iregex を使う。
% find dir/ -iname file.txt

Howto: 改行コード CRLF を含むファイルを検索する
カレントディレクトリ以下から、改行コードが CRLF を含むファイル名の一覧を表示する例。
% find . -type f | xargs grep -lUPz '\r\n'
Linux・FreeBSD いずれも使えるはず。

Howto: ファイルをタイムスタンプでソートする 2017-08-22 追加
GNU find なら -printf オプションを使えばよい。
% find . -type f -printf "%M %TY-%Tm-%Td %TH:%TM:%TS %p\n" | sort -k2,3
FreeBSD などは find に -printf オプションがないため、ls の --full-time に頼るのがよいだろう。
% find . -type f | xargs ls --full-time '%Y%m%d%H%M%S'|sort -k6,7

find と xargs の組み合わせ 【2017-06-10 -exec {} + を追加】
ソースの中から文字列「hogehoge」を検索するには
% find . -name \*.c -exec grep hogehoge {} \;
とすればよいが、これでは *.c のファイルの数だけ grep コマンドが実行され、時間がかかる。そういう場合は
% find . -name \*.c -print | xargs grep hogehoge
と xargs コマンドを使うとよい。ファイル名に空白などが含まれる場合は
% find . -name \*.c -print0 | xargs -0 grep hogehoge /dev/null
とするが (Linux・FreeBSD 等では使えるが、Solaris 等の find コマンドでは -print0 オプションは実装されていないと思われる)。

また、-exec {} + を使って
% find . -name \*.c -exec grep hogeehoge {} +
としても同じ効果がある。

find の -or オプションに括弧が必要な理由【2017-09-06 作成】
下記はファイル名が abc か def のファイル・ディレクトリを検索する。
% find . -name abc -or -name def
しかしながら、
% find . -name abc -or -name def -print
のように -print などのアクションを付けると def は表示されるが、abc は表示されないので、
% find . \( -name abc -or -name def \) -print
と -or 部分を括弧で書こうようにすればよい、の理由について詳しく説明しよう。

まず、
% find . -name abc -or -name def -print

% find . -name abc -or -name def -and -print
と解釈される (条件を単に並べたものは -and で結んだのと同じであるため)。さらに結合順序は OR より AND が優先であるため、
% find . -name abc -or \( -name def -and -print \)
となる。よって、abc にマッチした場合は -print されないが、def にマッチした場合は -print されるのである。

一方で、なぜ
% find . -name abc -or -name def
の場合は表示されるのか疑問に思う人もいるかもしれない。find は -print・-ls・-exec などのアクション指定がない場合は自動的に -print を追加するので、それならば
% find . -name abc -or -name def -print
と同じではないか、と。実際は -print を追加するときに与えられた条件全体を括弧で囲った上で、末尾に -print を追加するのため、
% find . \( -name abc -or -name def \) -print
となるので、正しく動くのである。

注意点: csh・tcsh における -exec {} のエスケープ 【2017-06-20 追加】
csh・tcsh における -exec・-ok の注意点について。

下記は *.txt を *.txt.bak にリネームする例であるが、sh・bash ではうまくいくものの、csh・tcsh ではリネーム先ファイル名がすべて ".bak" になってしまう。
% find .-name \*.txt -exec mv {} {}.bak \;
これは find コマンドに関係なくシェルの違いであり、sh・bash では
$ echo {} {}.bak
{} {}.bak
となるのに対し、csh・tcsh では
% echo {} {}.bak
{} bak
となるためである。

下記のようにエスケープすると意図通りに動く。
% find .-name \*.txt -exec mv {} \{}.bak \;
下記のように {} の前にはエスケープを常に付けてもよい。もちろん sh・bash でも動く。
% find .-name \*.txt -exec mv \{\} \{\}.bak \;

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

DOS・Windows の tree コマンドのような出力が欲しければ、tree コマンドを使うとよい。
% tree /usr
/usr/
|-- X11R6
| |-- bin
| | |-- ccmakedep
| | |-- (略)
| | `-- xmkmf
| |-- etc
| | |-- fonts
>> OSオンラインマニュアル(man) FreeBSD find(1)
>> OSオンラインマニュアル(man) Solaris10 find(1)
>> OSオンラインマニュアル(man) Linux find(1)

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

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

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

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

大学などでは fingerd が動いているところもあるかもしれないが、一般のプロバイダではまず fingerd は不要なサービスとして止められているだろう。
>> OSオンラインマニュアル(man) FreeBSD finger(1)
>> OSオンラインマニュアル(man) Solaris10 finger(1)
>> OSオンラインマニュアル(man) Linux finger(1)

flame フラクタル画像を描く

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

lex の上位互換プログラム。構文解析器の bison と組み合わせて使用されることが多い。bison とは異なり、flex は GNU のプロダクトではなく、GPL で配布されてもいない。
>> OSオンラインマニュアル(man) Linux flex(1)
>> OSオンラインマニュアル(man) FreeBSD flex(1)

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

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

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 指定されたコマンドを一括して実行する。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 が用意されている。

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 を愛用している。
>> OSオンラインマニュアル(man) FreeBSD freebsd-update(8)

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
>> OSオンラインマニュアル(man) FreeBSD from(1)

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

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

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

fsck を手動で実行する場合は、たくさんの質問が聞かれるが、UNIX に精通していないと質問の意味が理解にしくい。その場合 fsck -y で実行すると、全ての質問に yes と答えたことになる。
>> OSオンラインマニュアル(man) Solaris10 fsck(1m)
>> OSオンラインマニュアル(man) FreeBSD fsck(8)

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 というコマンドがインストールされている場合が多い。
>> OSオンラインマニュアル(man) FreeBSD fstat(1)
>> OSオンラインマニュアル(man) Linux fstat(2)

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 に記述しておく方法がある。
-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 でヒストリを利用できる
>> OSオンラインマニュアル(man) Linux ftp(1)
>> OSオンラインマニュアル(man) Solaris10 ftp(1)
>> OSオンラインマニュアル(man) FreeBSD ftp(1)

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

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

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

zip の伸張に関する詳細な説明は unzip を参照。

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 を使うこと。
>> OSオンラインマニュアル(man) FreeBSD fuser(1)
>> OSオンラインマニュアル(man) Solaris10 fuser(1M)

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

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

設定ファイルは~/.fvwmrc。

fvwm2 fvwmのバージョン2。

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

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

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

gas GNUアセンブラ

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

gawk GNU 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 などのデバッガを使う場合に有用な情報をバイナリに残しておく。
-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

ただし、静的リンクをすると
  • バイナリサイズが増加する
  • 複数のプロセス間で実行時にライブラリのメモリを共有できない(共有ライブラリにしておけば、テキスト領域の分だけメモリを共有できる)
  • ライブラリにバグがあったら、全バイナリをコンパイルしなおす必要がある
という欠点がある。
-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
-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 までコンパイルできるらしい。
>> OSオンラインマニュアル(man) Linux gcc(1)
>> OSオンラインマニュアル(man) FreeBSD gcc(1)

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

gdb デバッガ

16進数 → 10進数変換
% gdb
(gdb) print 0x1234
$1 = 4660
(gdb) p 0x1234 (print を省略して p でもよい)
$1 = 4660
>> OSオンラインマニュアル(man) FreeBSD gdb(1)
>> OSオンラインマニュアル(man) Linux gdb(1)

getopt 

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

ghostview は gs (ghostscript) の GUI インタフェースである。

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

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

当ページ管理人は簡単なバナーを作ろうと思ったが、何をどうすればよいのかわからず、結局 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 を使ってみるとよい。

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

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

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

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

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

grep ファイルから指定のパターンにマッチする行を検索する

UNIX/Linux の grep コマンドは、ファイルの中から指定の文字列を検索するコマンドである。複数ファイルからの検索や、複数条件での検索、正規表現のパターン指定、特定パターン除外指定、ディレクトリをたどる再帰的検索などを行うことができる。

目次:
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 に比べて高機能である grep (GNU grep) コマンドを標準採用しているが、Solaris などはデフォルトの grep は (GNU grep と比べると) 低機能で、-e オプションや -E オプションを使うことができない。Solaris の場合、/usr/xpg4/bin/grep が多少は高機能な grep となっているが、GNU grep ほどではない。

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

grep コマンドのオプション
-num マッチした文字列の前後 num 行を表示する。
デフォルトは -0。つまりマッチした行のみを表示するということ。
-A [num] または --after-context=[num]
マッチした文字列の後に続く num 行を表示する。
-B [num] または --before-context=[num]
マッチした文字列の前の num 行を表示する。
-a または --text
バイナリファイルであったとしても、テキストファイルのように扱う。grep コマンドはバイナリファイルに対してはマッチした行を表示するのではなく、一致したことだけを伝える。
% grep a /bin/ls
バイナリファイル /bin/ls に一致しました
→ または Binary file /bin/ls matches
しかしながら、テキストファイル内に一部不正データが混入している場合など、本当はテキストファイルとして扱ってほしい場合は、-a または --text オプションを使うことで、テキストファイルのように取り扱うことができる。バイナリファイル内の文字列を検索したい場合は string コマンドの使用を検討すること。
-b マッチした行のオフセット (開始バイト数) を表示
% grep -b foo sample.txt
0:foo
18:aafoobb
⇒ foo の行は sample.txt の 0バイト目から始まり、aafoobb の行は sample.txt の 18バイト目から始まることがわかる
-C -2と同じ
-c または --count
テキスト中に文字列が含む行の行数を表示する。-v と組み合わせると、含まない行数を表示する。
% grep -c hoge a.txt
5
→ a.txt には hoge を含む行が 5行ある
% grep -c -v hoge a.txt
8
→ hoge を含まない行は 8行ある
複数ファイルに対しても実行すると、ファイル名と行数を表示する。
% grep -c hoge *
a.txt:5
b.txt:9
c.txt:0
% grep -c hoge * | sort -t: -k2n
→ 行数の昇順でソート
-e [パターン] または --regexp=[パターン]
明示的に検索パターンを指定する。パターンは正規表現として扱われる。

パターンが 1つだけの場合、以下の 2つは同じである (-e オプションを付けても付けなくてもよい)
% grep hoge sample.txt
% grep -e hoge sample.txt

-e オプションは複数個のパターンを指定するときによく使用される。
例えば「rwx」または「r-x」を含む行を検索しようとして、
% ls -l | grep 'rwx' 'r-x'
とすると、grep は 「r-x」というファイルを見付けようとしてエラーになってしまう。こういう場合は -e オプションを複数個指定し、
% ls -l | grep -e 'rwx' -e 'r-x'
とすればよい。低機能版の grep には -e オプションは効かないので注意。
-E [パターン] または --extended-regexp=[パターン]
拡張正規表現を使う。デフォルトでは 「?+|{}()」などは普通の文字として扱われてしまうので、「foo」と「bar」を含む行を表示しようとして、
% grep 'foo|bar' sample.txt
としても、'foo|bar' という普通の文字列だと認識されてしまう。
% grep -E 'foo|bar' sample.txt
だと拡張正規表現として扱われるので、うまくいく。低機能版の grep には -E オプションは効かないので注意。grep -E は egrep とほぼ同じである。
-F 固定文字列として検索する。
. * ? などのメタキャラクタを指定しても、正規表現としての意味を持たなくなる。grep -F は、fgrep と同じである。
-f [file] または --file=[file]
ファイル file 中の文字列を検索パターンとして使う。
-h または --no-filename
出力行の先頭のファイル名を表示しない。grep コマンドのデフォルトでは
% grep hoge *.txt
sample1.txt: hogehoge
sample1.txt: aahoge
sample2.txt: hogefuga
のように、各行の先頭にファイル名を表示するが、-h オプションを使うと
% grep hoge *.txt
hogehoge
aahoge
hogefuga
というふうにファイル名表示を抑止する。
-i または --ignore-case
大文字小文字を区別しない。
-l 指定文字列を含むファイル名を表示。
指定の文字列を含むファイルが何個あるか数えるには
% grep -l hoge *.txt | wc -l
とする。
-L または --files-without-match
指定文字列を含まないファイル名を表示。
-n または --line-number
マッチした行の行番号を表示する。
% grep -n hoge *.txt
sample1.txt:26: hogehoge
sample1.txt:128: aahoge
sample2.txt:3 hogefuga
-P または --perl-regexp
Perl 互換の正規表現 (PCRE) を使う。
-r ディレクトリを再帰的にたどって、ファイルを検索する。
通常の場合は "grep PATTERN [対象ファイル]" であるが、-r オプションを指定した場合は "grep -r PATTERM [対象ディレクトリ]" とする。
% grep -r hoge .
→ カレントディレクトリ以下のファイルから再帰的に hoge を検索する
% grep -r hoge dir/ dir2/
→ ディレクトリ dir と dir2 以下のファイルから再帰的に hoge を検索する
-r オプションで再帰的に検索する場合は、--include オプション・--exclude オプション・--exclude-dir オプションで絞り込むのが便利である。こちら を参照してほしい。
-s または --no-messages
エラーメッセージを抑制する(ファイルに対しての permission denied など)。
-w または --word-regexp
ファイル中の指定文字列が独立している場合だけマッチしたものとみなす。
% cat test
sample // 独立した文字列ではないのでマッチしない
samp // 記号や空白でかこまれた文字列はマッチする
samp2 // 数字は記号とみなされない
,samp-
(samp&
samp/
% grep -w samp test
samp
,samp-
(samp&
samp/
-x または --line-regexp
指定文字列がそのまま1行にあるものだけマッチしたものとみなす。つまり
% grep -x abc

% grep '^abc$'
と等価。
-v または --invert-match
指定文字列を「含まない」行を表示 (正規表現にマッチしたら除外する)。
% grep -v hoge sample.txt
→ sample.txt の、hoge を含む行を除外し、それ以外を表示する。
-Z 圧縮したファイルを grep する。
% compress file.txt
% grep -Z hoge file.txt.Z
--line-buffered 出力バッファリングにおいて、行バッファリングとする。
例えば
% tail -f /var/log/syslog | grep hoge | grep -v fuga
のように tail の後に grep コマンドを 2段に重ねた場合、最初の grepコマンド が出力時にバッファリングを行なってしまうためログに追記された内容がすぐには表示されない。そのようなときは以下のように --line-buffered オプションを使うとよい (Linux と *BSD で使用可。FreeBSD は 5.3-RELEASE 以降)。
% tail -f /var/log/syslog | grep --line-buffered hoge | grep -v fuga

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

Howto: 検索結果にファイル名のみを表示する
-l オプションを使うことで、該当文字列が存在するファイル名のみを表示できる。
% grep hoge *.txt
sample.txt
sample2.txt

Howto: 複数条件 (OR 条件) での検索
-e オプションを複数指定することで、複数条件 (OR条件) を指定できる。
% grep -e aaa -e bbb -e ccc *.txt
正規表現で | でつなげてもよい。通常の grep なら \| とエスケープする。egrep なら | をそのままでよい。
% grep 'aaa\|bbb\|ccc' *.txt
% egrep 'aaa|bbb|ccc' *.txt

Howto: 複数条件 (AND 条件) での検索
grep をパイプで複数段つなげることで、AND 条件を指定できる。
% grep aaa *.txt | grep bbb | grep ccc
ただしこの場合は、「同一行に aaa と bbb と ccc が出現する行を検索する」という意味であることに注意。もし、「同一行でなくてもいいので、aaa と bbb と ccc が出現するファイル名を表示する」が目的であれば、-l オプションと xargs を使って、下記のようにすればよい。
% grep -l aaa *.txt | xargs grep -l bbb | xargs grep -l ccc

Howto: ディレクトリを再帰的に検索する
grep に -r オプションを付けることで再帰的にディレクトリをたどって検索することができる。
% grep -r hoge .
→ カレントディレクトリ以下のファイルから再帰的に hoge を検索する
% grep -r hoge dir/ dir2/
→ ディレクトリ dir と dir2 以下のファイルから再帰的に hoge を検索する
-r オプションで再帰的に検索する場合は、--include オプションと --exclude で絞り込むのが便利である。
% grep -r --include='*.log' hoge .
→ 対象ファイルを *.log に絞る
% grep -r --exclude='*.log' hoge .
→ *.log 以外のファイルを対象に検索する
--include オプションと --exclude オプションはファイルに対してしか効果がない。ディレクトリを除外したい場合は --exclude-dir オプションを使う。
% grep -r --exclude-dir='.svn' --exclude-dir='.git' .
→ .*.log 以外のファイルを対象に検索する
残念ながら --exclude-dir オプションは FreeBSD 11.0-RELEASE ではまだ使えないようだ。

Howto: 大文字小文字を同一視する
-i オプション指定することで、大文字小文字を区別しないようにできる。
% grep -i aaa *.txt
→ aaa でも AAA でも aAA でもマッチする。

Howto: プロセスの検索
現在実行中のプロセスから 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
でもよいのだけれど。
>> OSオンラインマニュアル(man) Solaris10 grep(1)
>> OSオンラインマニュアル(man) FreeBSD grep(1)
>> OSオンラインマニュアル(man) Linux grep(1)

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

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

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

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

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

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

gzcat は gzip -dc と同じである。

他の圧縮・伸長コマンドや、マルチコア対応版については下記項目を参照のこと。

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

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

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

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

他の圧縮・伸長コマンドや、マルチコア対応版については下記項目を参照のこと。
>> OSオンラインマニュアル(man) Linux gzexe(1)
>> OSオンラインマニュアル(man) FreeBSD gzexe(1)

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 コマンドがよく使われる。

オプション
-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 の開発を引き継いでやってください。

他の圧縮・伸長コマンドや、マルチコア対応版については下記項目を参照のこと。
>> OSオンラインマニュアル(man) Linux gzip(1)
>> OSオンラインマニュアル(man) FreeBSD gzip(1)

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
とすることで、できる限りのファイルを拾い出すことができるだろう。

他の圧縮・伸長コマンドや、マルチコア対応版については下記項目を参照のこと。

halo 画面にサークルを描く

halt シャットダウン

詳しい説明は shutdown の項を参照

hash bash のハッシュテーブル管理用コマンド。bash の内部コマンド。

bash においてコマンドを実行して、PATH からコマンドを見つけた場合、bash は内部のハッシュテーブルにコマンドのフルパスを登録し、次回以降はそのハッシュテーブルを活用する。

ハッシュテーブルは以下のように確認することができる。
$ ls
(略)
$ ls
(略)
$ date
(略)
$ hash
hits command
2 /bin/ls
1 /bin/date
hits は実行回数だが、特に意味はない。

注意点は、「実行することができた」コマンドのフルパスがハッシュテーブルに登録されていくことである。逆に言うと、存在しなかったコマンドの情報がハッシュテーブルに蓄積されることはない。

つまり、新しいパッケージをインストールし、これまで存在しなかった hogehoge というコマンドが /usr/bin/ に増えた場合、bash に特に指示をしなくても問題なく見つけることができる。一方で csh や tcsh のハッシュテーブルは、PATH の全ディレクトリの下にあるコマンドを覚えておくという方式なので、新コマンドが増えたら rehash コマンドを実行しないといけない。

よって、bash のハッシュテーブルでハマるのは、下記のように、実行ファイルを削除したが、同名の実行ファイルが別ディレクトリにも存在するときであろう (つまり、結構レアケースである)。
$ ls /bin/foo /usr/bin/foo
/bin/foo
/usr/bin/foo
→ /bin/foo と /usr/bin/foo が存在する
$ echo $PATH
/bin:/usr/bin/foo
→ PATH は /bin の方が先
$ foo
→ /bin/foo がハッシュテーブルに登録された
$ rm /bin/foo
→ /bin/foo を削除した (/usr/bin/foo はそのまま)
$ foo
bash: /bin/foo: No such file or directory
→ /usr/bin/foo は存在するのに、/bin/foo がないと言われてしまう

bash でハッシュテーブルを個別に削除
bash でハッシュテーブルを個別に削除するには、hash -d を実行すればよい。
$ hash
hits command
2 /bin/ls
1 /bin/date
$ hash -d ls
→ ls のハッシュを削除
$ hash
hits command
1 /bin/date
→ ls に関する情報が消えた

bash でハッシュテーブルを全クリア
bash でハッシュテーブル全体をクリアするには hash -r を実行すればよい。
$ hash -r
$ hash
hash: hash table empty
→ 空になった

shの場合
sh には上記のようなハッシュテーブルは存在しない。

csh・tcshの場合
csh・tcsh におけるハッシュテーブルは、bash とは微妙に異なる。詳細は rehash を参照。

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

ファイルの内容をダンプする。hexdump -C とまったく同じ。詳細は hexdump コマンドの項を参照。
>> OSオンラインマニュアル(man) Linux hd(4)

head ファイルの先頭部分を表示 (行数指定・バイト数指定)

UNIX/Linux の head コマンドは、ファイルの先頭部分を表示するコマンドである。表示する行数やバイト数を指定することができる。


head コマンドの基本的な使い方
head コマンドの使い方を説明する。

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

パイプ経由で、別コマンドの出力の先頭 10行を表示することもできる。
% sort -n data.dat | head
→ data.dat を数値としてソートし、先頭 10行を表示する

下記のように -[数字] または -n [数字] というオプションを指定することで、任意の行数を指定することができる。
% sort -n data.dat | head -20
% sort -n data.dat | head -n 30

head コマンドのオプション: 行数指定
-[数字] オプション: 表示する行数を指定
% cat sample.txt | head -30
→ 先頭の 30行が出力される
-n [数字] または --lines=[数字] オプション: -[数字] と同じく、ファイルの先頭の N 行を表示
% cat sample.txt | head -n 30
% cat sample.txt | head --lines=30
→ いずれも、先頭の 30行が出力される
--lines オプションが使えるのは主に Linux で使われている GNU Coreutils の head コマンドのみである。

head コマンドのオプション: バイト数指定
-c [数字] または --bytes=[数字] オプション: ファイルの先頭の指定 バイトを表示
% cat sample.txt | head -c 100
→ 先頭の 100バイトが出力される
% cat sample.txt | head --bytes=100
→ --bytes でも同じ
aa
--bytes オプションが使えるのは主に Linux で使われている GNU Coreutils の head コマンドのみである。

関連コマンド
「ファイルの末尾 n 行を表示」「ファイルの先頭 n 行以降を表示」または「ファイルの先頭 n行と末尾の m 行以外を表示」という場合は tail コマンドを使うとよい。
>> OSオンラインマニュアル(man) FreeBSD head(1)
>> OSオンラインマニュアル(man) Solaris10 head(1)
>> OSオンラインマニュアル(man) Linux head(1)

helix らせん模様を描く

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

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

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

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

数字を指定すると、現在からさかのぼってその数だけのヒストリを表示する。

hopalong フラクタル画像を描く

host 

hostname ホスト名を表示

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

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

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

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

UNIX/Linux における iconv コマンドは、ファイルの文字コード (エンコーディング) を変換するコマンドである。


iconv コマンドの基本的な使い方
iconv コマンドを使ってファイルの文字コードを変換する例を以下に示す。-f と -t オプションを使って、変換元文字コードと変換後文字コードの両方を指定する必要がある。
% iconv -f EUC-JP -t Shift_JIS < infile.txt > outfile.txt
⇒ infile.txt の文字コードを EUC-JP とみなし、Shift_JIS に変換して outfile.txt に出力する。
% iconv -f EUC-JP -t UTF-8 < infile.txt > outfile.txt
⇒ EUC-JP から UTF-8 に変換する。

FreeBSD など一部の iconv では、変換元か変換後のいずれかの文字コードを省略した場合、環境変数 LC_ALL や LANG などに設定されているロケールを使用するが、すべての iconv でそのような挙動をするとは限らない。

不正文字の扱い
入力ファイルに無効な文字 (-f で指定した文字コードと矛盾するようなデータ) が含まれていた場合や、-f で指定した文字コードを -t で指定した文字コードで変換できない場合、iconv コマンドはエラーとして終了してしまう。例えば、「草なぎ剛」の「なぎ」は JIS X 0213 に含まれる文字であるが、Shift_JIS には含まれていない。そのため、
% echo '草なぎ剛' | iconv -f utf-8 -t shift_jis
iconv: 位置 3 で不正な入力シーケンスがありました
のように UTF-8 を Shift_JIS に変換しようとすると、エラーとなってしまう (本サイトは EUC-JP で記載されているので、やむを得ず「草なぎ」と表記したが、実際に試す際は「なぎ」を漢字にしてほしい)。同様に、ギリシャ数字の I・II や、いわゆる「はしご高」も同じようにエラーになる。

FreeBSD・Linux・Solaris など多くの iconv では -c オプションを指定することで、無効な文字を無視して続行することができる (2000年頃は Solaris の iconv コマンドでは -c オプションが使えなかった気がするが、Solaris10 では問題なく使えるようだ)。しかしながら不正データをスキップしてしまうため、
% echo '草なぎ剛 | iconv -c -f utf-8 -t shift_jis | iconv -f shift_jis -t utf-8
草剛
のように UTF-8 → Shift_JIS → UTF-8 とすると、変換できなかった文字が欠落してしまう。

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

もし上記で見つからない場合、日本において使用頻度が高いと思われる文字コードを以下に示すので、いろいろ試してほしい。なお、いわゆる機種依存文字を扱う場合は、UTF-8、CP932、EUCJP-WIN、SJIS-WIN などを使うことになると思われる。
  • UTF-8、UTF8
  • UTF-16、UTF16
  • EUC-JP、EUCJP、EUCJP-WIN、EUC-JISX0213
  • Shift_JIS、sjis、SJIS-WIN、SHIFT_JISX0213、CP932、MS932
  • ISO-2022-JP、ISO-2022-JP-2、ISO-2022-JP-3

一般的には IANA が管理する "Character Sets" での定義が正であるはずだが、登録却下されたはずの ISO-2022-JP-3 が FreeBSD や Linux の iconv で使えるようなので、独自拡張しているのかもしれない。

//IGNORE と //TRANSLIT
GNU iconv のみの実装かもしれないが、文字コードの末尾に //IGNORE や //TRANSLIT を付けることができる。//IGNORE は不正コードが見つかった場合、その文字を破棄し、最後にエラー出力する (-c オプションと似ている)。一方、
//TRANSLIT は近しい文字に置換を試みるが、近しい文字がなかった場合は「?」に置換する。
% cat i ii iii (株) 高 | iconv -f utf-8 -t shift_jis//TRANSLIT
i ii iii (株) 高
→ ギリシャ数字や(株)・はしご高などが、近しい文字に置換される (本サイトは EUC-JP で記載されており、ギリシャ数字などをそのまま書くことができないので雰囲気だけ掴んでほしい)

FreeBSD の iconv
少なくとも FreeBSD 10-RELEASE より iconv が libc に含まれるようになった。それ以前は port/package にて GNU iconv が使われていたような気がする。

関連コマンド
iconv コマンドはファイル内容のエンコーディングを変換するコマンドである。「ファイル名」のエンコーディングを変換する場合は、convmv コマンドを使うこと。

iconv コマンドはロケールの仕組みにのっとった正統派文字コード変換コマンドと言える。nkf コマンドや qkc コマンドは日本語専用のため、便利ではあるが正統派とはいえないが、nkf コマンドなどは自動で文字コードを推測してくれるなどの便利機能があるので、用途によって使い分けるとよい。
>> OSオンラインマニュアル(man) Linux iconv(3)
>> OSオンラインマニュアル(man) Linux iconv(1)
>> OSオンラインマニュアル(man) Solaris10 iconv(1)

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つのグループに属していることがわかる。
>> OSオンラインマニュアル(man) FreeBSD id(1)
>> OSオンラインマニュアル(man) Linux id(1)

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

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

もともとは HP-UX にあったコマンドで、他の

if sh・bash の if文 (if・then・elif・else・fi)

if コマンドは、sh・bash において条件判定を行うための内部コマンドである。

この項では、if 文自体の説明を行う。もし、
if [ "$foo" = "bar" ]; then
などの条件の書き方について調べている場合は、test コマンドの項を参照してほしい。

また、csh・tcsh の if についてはこの項では述べない。

if文のパターン
if文のパターンは下記のとおり。

▼cond1 なら cmd1 を実行する。
if cond1; then cmd1; fi
▼cond1 なら cmd1 を実行し、そうでないなら cmd2 を実行する。
if cond1; then cmd1; else cmd2; fi
▼cond1 なら cmd1 を実行し、そうでなく cond2 なら cmd2 を実行する。
if cond1; then cmd1; elif cond2; then cmd2; fi
▼cond1 なら cmd1 を実行し、そうでなく cond2 なら cmd2 を実行し、いずれでもないなら cmd3 を実行する。
if cond1; then cmd1; elif cond2; then cmd2; else cmd3; fi
elif〜then は何個でも重ねることができる。
if cond1; then cmd1; elif cond2; then cmd2; elif cond3; then cmd3; else cmd4; fi
elseif でも elsif でも else if でもなく、elif であることに注意。

上記はあえて 1行で書いてみたが (1行で書く際は、「then と elif と else の後ろにはセミコロン不要」と覚えよう)、よくある書き方は下記だろうか。
if cond1; then
cmd1
elif cond2; then
cmd2
else
cmd3
fi

さらに行を分けていくと、最終的にはセミコロンが不要となる。
if
cond1
then
cmd1
elif
cond2
then
cmd2
else
cmd3
fi

なお、
if cond1; then cmd1; fi
の cond1・cmd1 は、正確には list である。ここでいう list は「0個以上のコマンドをセミコロン・改行・&&・||・& でつなげたもの」。よって、
if ls; date; pwd; then cal; hostname; whoami; fi
という書き方もできる。

then や else 直後の空ブロック
由緒正しい sh では、then や else の後を空にすることができるので、
if [ .... ]; then
# 〜〜なので何もしない
else
...
fi
と書けるが、bash ではエラーになる。そのような場合は
if [ .... ]; then
# 〜〜なので何もしない
:
else
...
fi
と空コマンド (:) を入れておくとよい。

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 に書いておくことで、ブート時に毎回自動的に設定される。
>> OSオンラインマニュアル(man) FreeBSD ifconfig(8)
>> OSオンラインマニュアル(man) Solaris10 ifconfig(1m)

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

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

ImageMagick バージョン7 以降の注意点
ImageMagick バージョン7 より、convert 等のコマンドがなくなり magick コマンドに変更されている。Windows で関係ない convert コマンドが存在し、混乱を招くため。2017年9月現在、FreeBSD では ImageMagick がバージョン6、ImageMagic7 がバージョン7 として ports/packages が用意されている。

Magick について
ImageMagick は "Magic" ではなく "Magick" であることに注意。"magick" は "magic" の初期近代英語時代のスペルで、「魔術」という意味の英単語である。

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

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

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

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

imsmap フラクタル画像を描く

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 コメントを
/*
......
*/
という形式にする。

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

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

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

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

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 の操作方法は異なるようだ。

その他のキーバインドは、最低以下のものを知っておいてほしい。
  • 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 に満足しているのだろうか?
>> OSオンラインマニュアル(man) FreeBSD info(1)

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 などの細かな設定を行うことができる。

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

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

jlatex TeX コンパイラ

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

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 の項で行う。

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 の項を参照。

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 の処理に戻る

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 を使うとよい。
-w 書式文字列
printf(3) で指定できる書式文字列を与えることで、生成するデータの書式を指定できる。
% jot -w %03d 5
001
002
003
004
005
% touch `jot -w file%03d.txt 999`
⇒ file001.txt〜file999.txt を作成する。
jot コマンドが含まれる OS
jot コマンドは 4.2BSD で実装されたため、FreeBSD・NetBSD・OpenBSD などの BSD 系 OS で使うことができる。Linux や、SystemV 系 UNIX ではおおむね使うことができないと思われる。Linux では seq コマンドを使うとよい。
>> OSオンラインマニュアル(man) FreeBSD jot(1)

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 を書き換えること。

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 によって強制的に終了させられる。
>> OSオンラインマニュアル(man) FreeBSD kill(1)
>> OSオンラインマニュアル(man) Solaris10 kill(1)
>> OSオンラインマニュアル(man) Linux kill(2)
>> OSオンラインマニュアル(man) Linux kill(1)

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 に慣れている人は注意した方がよいだろう。
>> OSオンラインマニュアル(man) FreeBSD killall(1)
>> OSオンラインマニュアル(man) Linux killall(1)

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 などで調べることができる。
-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 コマンドでファイルを見るとよい。
-C コンソールのメッセージを表示する (/dev/console 宛に出力された文字も出力されるようになる)
-cr colorname カーソル部分の色を指定する。
-hc colorname マウスでドラッグした部分の色を指定する。
このオプションは xterm のみ使用可で、kterm では使えないらしい。色の名前は 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 に記述すること。
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
と書いておくとよい。

last 過去のブート、シャットダウン、ログインの記録を表示

% last user
⇒ ユーザ名 user のログイン情報を表示
>> OSオンラインマニュアル(man) FreeBSD last(1)
>> OSオンラインマニュアル(man) Linux last(1)

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 でシステムのログを作成しておく必要がある。
>> OSオンラインマニュアル(man) FreeBSD lastcomm(1)

ld リンカ。リンクエディタ

>> OSオンラインマニュアル(man) Linux ld(1)
>> OSオンラインマニュアル(man) Solaris10 ld(1)
>> OSオンラインマニュアル(man) FreeBSD ld(1)

ldconfig 共有ライブラリを検索するパスを設定

ldd で説明したダイナミックリンクは、ライブラリがどのディレクトリに置いてあるかという情報が必要になる。一般的には /usr/lib、/usr/X11R6/lib、/usr/local/libなどに共有ライブラリが置かれている。
>> OSオンラインマニュアル(man) FreeBSD ldconfig(8)
>> OSオンラインマニュアル(man) Linux ldconfig(8)

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
となる。
>> OSオンラインマニュアル(man) FreeBSD ldd(1)
>> OSオンラインマニュアル(man) Solaris10 ldd(1)
>> OSオンラインマニュアル(man) Linux ldd(1)

leave ログアウトする予定の時間を知らせる

% leave 1630
午後4時30分にログアウトする予定。5分前にアラームとメッセージが表示され、4時30分にもアラームとメッセージで時間になったことを知らせる。その後1分おきにアラームとメッセージを表示する。
% leave +30
今から30分後にログアウトする予定
>> OSオンラインマニュアル(man) FreeBSD leave(1)

less ファイル表示プログラム (ページャ)

あるコマンドを実行結果や、ファイルの内容を見たいとき、1画面に収まりきらずスクロールしてしまって最初の部分が見えないことがある。そういう場合、
% ls -l | less

% less file.txt
などとすることでゆっくり見ることができる。

more ではできなかったバックスクロールに対応、他にも gzip や compress で圧縮されたファイル (*.gz や *.Z) を直接見ることができるなど、いろいろな機能が付け加えられている。なお、FreeBSD の less は日本語を表示できないので、jless (ja-less) を使うこと。

最初に使うときは
  • q で終了 (more と違って、less はファイルの最後に到達しても終了しない)
  • カーソルキー・Ctrl-p・Ctrl-n で上下スクロール
  • <・>で先頭行・最終行に移動
  • / で検索 (正規表現として扱われる)
ということを覚えておくとよい。

less コマンドのキーバインド
less コマンドのキーバインドについて説明する。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とは逆方向に次検索
▷ F
tail -f のように、追記部分を順次表示する。Ctrl-C で tail -f モード終了。
▷ ESC-u
検索にマッチした部分の反転表示を解除
▷ v
エディタを起動して現在表示しているファイル編集
▷ = または ^G または :f
現在位置の行数、バイト数、パーセンテージを表示する。
lines 1-36/1453 byte 1834/68190 2%
→ 全体で1453行あるうち、現在1行目から36行目を表示している。全体サイズは68190バイトだが、画面最下行は1834バイトで、全体の2%を表示している
▷ -[オプション]
起動後に less オプションを指定する。例えば less 起動後に行番号表示の -N オプションを指定し忘れていたことに気づいた場合、less を起動したまま -N とすると、最下行にて
Constantly display line numbers (press RETURN)
と表示され、ENTER キーを押せば行番号が表示されるようになる。もう一度 -N とすると行番号が非表示になる。
▷ h
簡易ヘルプを表示
▷ V
バージョンを表示
▷ !(リターン)
シェルを起動
▷ !コマンド
コマンドを実行
▷ !!
直前の!コマンドを再実行

less コマンドのオプション
less コマンドのオプションは以下のとおり。なお、less 起動時にオプションを付け忘れた場合でも、less 起動後に -[オプション] として後から指定することもできる。
-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 [パターン] 起動後、指定されたパターンをサーチする。例えば less -p abc file.txt と起動するのは、less file.txt と起動した後に / で検索し abc と入力するのと同じである。マッチした部分が反転し、n を押下することで次のマッチ箇所に移動できるので、最初から検索したい文字列がわかっている場合は有用である。
-q エラーの際にあまりビープ音を鳴らさない (状況による)
-Q エラーの際にビープ音を鳴らさない
-r コントロールコードをそのまま表示する。デフォルトでは control-A は ^A と表示されるが、-r を指定するとそのまま表示する。これによって、cat で日本語が表示できる環境なら、less -r で日本語が表示できるかも。
-s 連続する空行を1つにまとめる
-S 1行の文字数が画面の横幅を超えた場合、折り返さず、はみでた部分は表示しない
-V バージョンを表示
-w 空行を表す記号に~を表示しない
-xn(数字) タブ幅をnに設定する。デフォルトは 8
-zn(数字) f キー、b キーを押した時にスクロールする行数を指定する。n がマイナスなら (スクリーンの縦幅-n) 行スクロールする

環境変数 LESS にオプションを設定することで、デフォルトオプションとして扱われる。例えば
% setenv LESS -Ngj10 (csh・tcsh の場合)
% export LESS=-Ngj10 (sh・bash の場合)
などと設定する。

なお、less を使わなくても kterm なら Shift+PageUp、Shift+PageDown、Tera Term なら Ctrl+PageUp、Ctrl-PageDown でさかのぼることもできるので、覚えておくとよいだろう。
>> OSオンラインマニュアル(man) Linux less(1)
>> OSオンラインマニュアル(man) FreeBSD less(1)

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 と組み合わせて使うと簡単なインタプリタくらいなら手軽に作ることができる。
>> OSオンラインマニュアル(man) Solaris10 lex(1)

lha LHA・LZH ファイルの管理ツール

l アーカイブされているファイルの一覧を表示
x アーカイブされているファイルを展開

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メガバイト
などと指定する。

lint Cプログラムの文法チェッカ

listres ウィジェットリソースのリストを表示

はっきり言って、何のためのコマンドなのかわかりまへん。

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 はシンボリックリンクの指す先ではなく、リンク自体を削除する。

シンボリックリンクのパーミッション
シンボリックリンク自体のパーミッションは全く意味を持たない。
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 のパーミッションである。

オプション
-f すでにリンクが張られていたら、リンクを付け替える。
% ln -s file link
% ln -s file2 link
ln: link: File exists
このようにリンクの「張り替え」のような作業をするとエラーとなるが -f オプションを付けると、この「張り替え」ができるようになる。
-s シンボリックリンクを張る。-s を付けないとハードリンクとなる。
>> OSオンラインマニュアル(man) FreeBSD ln(1)
>> OSオンラインマニュアル(man) Solaris10 ln(1)
>> OSオンラインマニュアル(man) Linux ln(1)

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 デーモンである。

OS インストール直後はデータベースファイルが作成されていないので、直接 /usr/libexec/locate.updatedb を実行すればよい。本当は nobody 権限で実行するのが一番よいが、locate.updatedb(8) を参照。

なお、/etc/locate.rc を書き換えることで、あるディレクトリ以下は検索対象に含めない、という設定をすることもできる。
>> OSオンラインマニュアル(man) FreeBSD locate(1)

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 を使うとよい。

look 英単語のつづりを調べる。

例えば「レシーブ」のつづりが「receive」「recieve」「reseive」のどれが正しいかわからない場合、
% look reseive
⇒ 何も出力されない (=そんな英単語はない)
% look recieve
⇒ 何も出力されない (=そんな英単語はない)
% look receive
receive
received
receivedness
receiver
receivership
⇒ 出力された。
となるため receive が正しいことがわかる。辞書は (FreeBSD の場合は) /usr/share/dict/words に置かれている。
>> OSオンラインマニュアル(man) Linux look(1)
>> OSオンラインマニュアル(man) FreeBSD look(1)

ls ファイル・ディレクトリを表示

UNIX/Linux における ls コマンドは、ファイル・ディレクトリの一覧や、詳細情報を表示するコマンドである。パーミッション・ファイルサイズ・タイムスタンプ・オーナー・グループなどの情報を表示することができる。ls コマンドは古くから存在するため、あらゆる UNIX/Linux 系 OS で使用可能である。


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"
とすればよい。

ls コマンドのオプション
-a 「.」 から始まるファイルも表示。「.」「..」も表示する。
-A 「.」 から始まるファイルも表示。「.」「..」は表示しない。
root が ls を実行した場合、常に -A オプションが付けられたものとして動作する。
-l ファイル、ディレクトリの詳細な情報を表示する
-T タイムスタンプを年月日時分秒まで表示 (要 -l オプション)
-o ファイルフラグを表示。BSD 系のみ (要 -l オプション)
-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/* と同じような動作をするが、-d オプションを付けると、
% ls -ld /usr/bin
drwxr-xr-x 2 bin bin 5120 Oct 7 05:26 /usr/bin
と、ディレクトリ自体の情報を表示する
-f ファイル名をソートせずに表示
--full-time ファイルのタイムスタンプを全て表示する。
年月日時分秒・ナノ秒単位で表示する。タイムゾーンも表示される。ただし主に Linux で使われる GNU Coreutils の ls のみ使用可能であることに注意。
% ls --full-time
-rwxrwxr-x 2 user group 9282 2017-06-12 05:59:47.130527880 +0900 file1.txt
-rwxr-xr-x 6 user group 4096 2017-01-11 20:03:09.529820000 +0900 file2.txt
UTC で取得したい場合は下記のように環境変数 TZ を設定するとよい。
% env TZ=UTC+0 ls --full-time
シェルスクリプトから正確なタイムスタンプを扱う場合は stat コマンドも参照してほしい。
-r 逆順にソートして表示
-t ファイルを変更した日時の順でソートする。最近どのファイルが更新されたか調べたいときは
% ls -lt | head
最近どのファイルが参照されたかを調べたいときは
% ls -lut | head
が便利。
-i ファイルの i-node を表示
先頭にファイル・ディレクトリの i-node を表示する。
% ls -li
22328145 drwxr-xr-x 2 68user realuser 512 5 29 10:37 dir
22335070 -rw-r--r-- 1 68user realuser 2159 5 29 10:37 file1.txt
上記例だと 22328145 や 22335070 が i-node である。

-l オプションなしで ls -i とすると、下記のような表示になる。
% ls -li
22328145 dir 22335070 file1.txt
-s 各ファイルのファイルシステムブロックの使用量を表示 (512バイト単位)
たとえ1バイトのファイルでも1ブロック (512バイト) を消費している。その消費量を表示する。ブロックの単位は環境変数 BLOCKSIZE で設定できる。
-k -s オプションが指定された場合、使用量を 1K バイト単位で表示する
-x ファイルを横方向ではなく、縦方向にソートする
(-x オプションは SystemV 系と GNU の ls のみ)。
-q ファイル・ディレクトリ名の中に表示不可能な文字があった場合、`?' という文字に置き換えて表示する。このオプションはデフォルトで有効になっている。このおかげで日本語を含むファイル名を ls で表示しようとすると、???? などとなってしまう。この機能は、出力先がパイプやファイルだと抑制されるので、
% ls | less
% ls | cat
などとすると、日本語ファイル名を表示できる。

Howto: ls コマンドの出力結果を更新日時でソートする
ls -ltr をおすすめする。下記は最終変更時刻の昇順でソートしたもので、一番下に新しいものが表示される。
% ls -ltr
-rw-r--r-- 1 68user realuser 38671 May 28 15:01 sample.dat
-rw-r--r-- 1 68user realuser 22354 May 29 17:19 sample.txt
-rw-r--r-- 1 68user realuser 1269927 May 29 17:22 sample2.dat
-rw-r--r-- 1 68user realuser 83771 May 29 17:20 sample.html
drwxr-xr-x 3 68user realuser 512 May 29 19:43 sample.xxx

Howto: ls コマンドの出力結果をファイルサイズ順でソートする
ls -lSr をおすすめする。下記はファイルサイズの昇順でソートしたもので、一番下にファイルサイズが大きいものが表示される。
% ls -ltr
drwxr-xr-x 3 68user realuser 512 May 29 19:43 sample.xxx
-rw-r--r-- 1 68user realuser 22354 May 29 17:19 sample.txt
-rw-r--r-- 1 68user realuser 38671 May 28 15:01 sample.dat
-rw-r--r-- 1 68user realuser 83771 May 29 17:20 sample.html
-rw-r--r-- 1 68user realuser 1269927 May 29 17:22 sample2.dat
-S オプションは、少なくとも Linux・*BSD の ls で使用可能である。FreeBSD では 6.0-RELEASE 以降で対応している。

Howto: ls コマンドのファイルサイズ表示をわかりやすくする
ls -lh とすることで、ファイルサイズが K・M・G などの SI 接頭辞付きで表示される。
% ls -lh
-rw-r--r-- 1 68user realuser 37.7K May 28 15:01 sample.dat
-rw-r--r-- 1 68user realuser 81.8K May 29 17:20 sample.html
-rw-r--r-- 1 68user realuser 21.8K May 29 17:19 sample.txt
drwxr-xr-x 3 68user realuser 512 May 29 19:43 sample.xxx
-rw-r--r-- 1 68user realuser 1.2M May 29 17:22 sample2.dat
ls -lhS で、ファイルサイズでソートしつつ、K・M・G 表記で表示することができる。

-S オプションは、少なくとも Linux・*BSD の ls で使用可能である。FreeBSD では 6.0-RELEASE 以降で対応している。

関連コマンド
ファイルの詳細情報を取得したい場合、stat コマンドも参考にしてほしい。
>> OSオンラインマニュアル(man) Linux ls(1)
>> OSオンラインマニュアル(man) Solaris10 ls(1)
>> OSオンラインマニュアル(man) FreeBSD ls(1)

lsdev 現在のシステムで有効なデハイスを表示

-t class 指定したタイプのデバイスを表示。
class に指定できるのは、cpu、isa、eisa、pci、scsi、disk、bus。
-c カーネル設定ファイルと同じような書式で出力
>> OSオンラインマニュアル(man) Linux lsdev(8)

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 で設定できる。

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 を使って実現してみよう、というのが目的である。

結果として、以下の機能変更を行った。
  • m4 ではコロンを含むマクロ名は使えないので、アンダーバーから始まるマクロ名に変更した。
  • 「:cmd 〜 :cmd で囲む」といった状態保持が必要な書き方は m4 的ではないので、「_CMD_BEGIN 〜 _CMD_END で囲む」に変更した (define で現在の状態を保存すれば、トグル的な動作も可能だろう)。
そしていろいろ試行錯誤してみたが、FreeBSD 5.2.1-RELEASE の m4 では、以下の機能は実現できなかった。
  • 「:preincude ファイル名 42-45」と書くとソースファイル中の指定した行番号部分が取り込まれる
  • 「:preincude ファイル名」で取り込んだソース中の <・> を &lt;・&gt; に置換する
最終的に作成した m4 マクロは以下の通り。
define(_HTML_BEGIN, `<HTML><HEAD><TITLE>$*</TITLE></HEAD><BODY><H1>$*</H1>')
define(_HTML_END, `<P CLASS="cvsid"><A HREF="_CVSWEB_URL">_CVSID</A></P></BODY></HTML>')
define(_TERM, `<H2>$*</H2>')
define(_CMD_BEGIN, `<PRE class="cmd">')
define(_CMD_END, `</PRE>')
define(_CODE_BEGIN, `<PRE class="code">')
define(_CODE_END, `</PRE>')
define(_PREINCLUDE, `<PRE class="code">syscmd(cat -n $1)</PRE>')
define(_CVSID, `$Id: prgmemo.src,v 1.86 2017/07/22 11:11:00 68user Exp $')
define(_CVSWEB_URL, `../cgi-bin/cvsweb.cgi/public_html/net/org/'__file__)
m4wrap(`_HTML_END')

_HTML_BEGIN(`RSA で暗号化してみよう (2)')
_TERM(`自分で暗号化・復号化')

前ページで作成した (略) 実行結果は以下の通り。

_CMD_BEGIN
% cc -o rsa-2 rsa-2.c -lcrypto
(略)
_CMD_END

まずは RSA の鍵生成です。前ページの rsa-1.c では

_CODE_BEGIN
RSA *rsa = RSA_generate_key(KEYBIT_LEN, 65537, NULL, NULL);
_CODE_END

だけで済んでいましたが、今度は自分で計算しなくてはいけません。

_PREINCLUDE(`rsa-2.c')
(略)

以下、落ち穂拾い。

コメント
m4 のコメントは # から行末までである。ただしマクロ解析の対象とならないだけで、コメントもそのまま出力されてしまうことに注意。
% m4
> #hogehoge
#hogehoge
出力したくないコメントは
divert(-1)
# コメント
# コメント
divert(0)dnl
とすればよい。意味については組み込みマクロ divert の項を参照。
dnl
dnl は「Delete through NewLine」の略で「ここから行末まで破棄」という意味である。例えば define でマクロを定義すると、余分な空行が出力されることに気がついただろうか。
% m4
> define(foo, bar)
← この空行は何?
> foo
bar
m4 は入力された文字をそのまま出力しようとするため、define(foo, bar) の後に入力した改行コードがそのまま出力されたのである。これを防ぐには
% m4
> define(foo,bar)foo
bar
と続けて書けばよいが、これでは見づらくて仕方がない。そこで、
% m4
> define(foo, bar)dnl
> foo
bar
と define の後に dnl を付けて、「ここから行末まで破棄しなさい」と m4 に指示することで余計な改行コードが付かないようにすることができる。

組み込みマクロ一覧 (未稿)
divert・undivert
m4 には 0〜9 までの出力キューが存在する。デフォルトは 0 で、
% m4
> hoge
hoge
は出力キュー 0 に対して「hoge」を出力し、即座に画面上に表示されたということである。divert マクロによって出力する出力キューを選択できる。全ての処理が終了した後、1〜9 の出力キューの中にたまっているキューの内容が、出力キュー 1→9 の順で出力される。
% m4
> divert(2)
> this is queue 2
⇒ 出力キュー 2 にためている
> divert(1)
> this is queue 1
⇒ 出力キュー 1 にためている
> divert(0)
> this is queue 0
this is queue 0
⇒ 出力キュー 0 はすぐ出力される
^D (Ctrl-d で標準入力をクローズ)
this is queue 1
this is queue 2
⇒ 出力キュー 1〜9 の内容が出力される
任意の時点で出力キューの内容を取り出したい場合は、undivert すればよい。
% m4
> divert(2)
> this is queue 2
⇒ 出力キュー 2 にためている
> divert(0)
⇒ 出力キューを 0 に切り替え
> undivert(2)
⇒ 出力キュー 2 の内容を現在の出力キュー (キュー 0) に移動。結果として画面に出力される
this is queue 2

> divert(3)
this is queue 3
⇒ 出力キュー 3 にためている
> divert(1)
⇒ 出力キューを 1 に切り替え
> undivert(3)
⇒ 出力キュー 3 の内容を現在の出力キュー (キュー 1) に移動。
> divert(0)
⇒ 出力キューを 0 に切り替え
> undivert(1)
this is queue 3
⇒ 出力キュー 1 の内容を現在の出力キュー (キュー 0) に移動。結果として画面に出力される。キュー 3 に出力した内容がキュー 1 から出てきたことに注意。
include
ファイルを取り込む。ファイルが存在しなかったらエラー。
sinclude
ファイルを取り込む。ファイルが存在しなかったら sinclude がなかったものとして続行する。
syscmd
コマンドを実行する。実行結果はマクロ展開対象とはならない。
esyscmd
コマンドを実行する。実行結果はマクロ展開対象となる。

>> OSオンラインマニュアル(man) FreeBSD m4(1)

mail 簡易的なメーラー

% mail foo@example.com < file
file の内容を foo@example.com に送る
% mail -s hoge foo@example.com < file
さらにサブジェクトを hoge とする

日本語を含んだメールを送る場合は、必ず nkf コマンドなどで文字コードを ISO-2022-JP(いわゆる JIS コード) に変換すること。
% nkf -j < file | mail -s "HOGE FUGA" foo@example.com
>> OSオンラインマニュアル(man) Solaris10 mail(1)
>> OSオンラインマニュアル(man) FreeBSD mail(1)

make 依存関係を調べて最適な実行をする。

一般的には、プログラムをコンパイルする際に、Makefile というファイルに依存関係を記述し、make に自動的にコンパイルさせる、といった使い方をする。一括処理をさせるだけならシェルスクリプトを使えばよいのでは?、と思うかもしれないが、make はファイルの依存関係と それらのタイムスタンプを調べ、必要な処理だけを行うという機能を持っている。

例えば program というコマンドのソースが、source-1.c、source-2.c、source-3.c、program.h という 3つのソースファイルと1つのヘッダファイルから構成され、各 source-*.c の中で program.h を include しているとする。一括してコンパイルしたい場合は
% cc -o program source-1.c source-2.c source-3.c
とすればよいが、あるソースファイルだけを書き換えた場合でも、全てのソースをいちいちコンパイルすることになり、時間の無駄である。そこで Makefile というファイルを作成し、その中に
program: source-1.o source-2.o source-3.o
cc -o program source-1.o source-2.o source-3.o
source-1.o: source-1.c program.h
cc -c source-1.c
source-2.o: source-2.c program.h
cc -c source-2.c
source-3.o: source-3.c program.h
cc -c source-3.c
と書いておく。
  • 1行目は、program は source-1.o、source-2.o、source-3.o から構成される
  • 2行目は、program を作成するには cc -o program ... とすればよい
ということを示している。その後の行も同じく、
  • source-1.o は source-1.c と program.h から構成される
  • source-1.o を作成するには cc -c source-1.c とすればよい
ということを表す。一般的には Makefile は
ターゲット: 依存するファイル
(TAB)ターゲットを作成するためのコマンド
という情報の羅列である。なお、TAB の部分は必ず TAB にしなければならない (スペースではダメ)。

何もない状態 (コンパイルしていない状態)で make を実行すると、カレントディレクトリの Makefile が読まれ、最初に出てくるターゲット名 (この場合は program) を作成しようとする。よって
% make
cc -c source-1.c
cc -c source-2.c
cc -c source-3.c
cc -o program source-1.o source-2.o source-3.o
が実行される。ここで source-1.c の内容を書き換えたとしよう。ファイルが更新されたので、source-1.c のタイムスタンプが新しくなった。再度 make を実行すると、make は各ファイルのタイムスタンプを調べる。その結果 source-1.o より source-1.c が新しいので
% make
cc -c source-1.c
cc -o program source-1.o source-2.o source-3.o
と、source-2.c と source-3.c は再コンパイルせず、必要なコンパイルだけを実行してくれる。一方、program.h を書き換えた場合は、全てのソースがこのヘッダファイルを参照しているため、
% make
cc -c source-1.c
cc -c source-2.c
cc -c source-3.c
cc -o program source-1.o source-2.o source-3.o
と、全てのファイルがコンパイルし直される。

サフィックスルール
さて、先程の Makefile だが、同じファイル名が何度も繰り返し現れ、非常に無駄が多い。もう少し短くまとめてみよう。make が力を発揮するのは、サフィックス (拡張子) の関係を指示したときである。拡張子と拡張子との関係を「サフィックスルール」という。

ここで *.o は *.c から生成されることに着目しよう。特に、source-1.o は source-1.c から作られ、source-2.o は source-2.c から作られ…というふうに、foo.c → foo.o のように拡張子のみが段階的に変わっていくことに注目してほしい。

そこで役に立つのがサフィックスルールである。
.SUFFIXES : .c .o
.c.o:
cc -c $<
と書くと、*.c についてそれぞれ cc -c を実行し、*.o を作成してくれる。$< は現在のターゲットを表している。つまり、
program: source-1.o source-2.o source-3.o
cc -o program source-1.o source-2.o source-3.o
.SUFFIXES : .c .o
.c.o:
cc -c $<
と Makefile に記述した場合、
  • program は source-1.o source-2.o source-3.o から作成される
  • source-1.o は source-1.c から作成される
  • source-2.o は source-2.c から作成される
  • source-3.o は source-3.c から作成される
ということを表している。ここで source-3.c だけを更新して make すると
% make
cc -c source-3.c
cc -o program source-1.o source-2.o source-3.o
が実行されるが、このとき make は以下のような順番で依存関係のチェックを行う。
  • program は source-1.o source-2.o source-3.o から作成されるので、*.o を新たに作成すべきかどうか調べる
  • .c.o: により、source-1.o は source-1.c から作成されることを知り、source-1.c のタイムスタンプを調べる → source-1.o の方が新しい → コンパイルする必要なし
  • 同様に source-2.o は source-2.c から作成されることを知り、source-2.c のタイムスタンプを調べる → source-2.o の方が新しい → コンパイルする必要なし
  • source-3.o は source-3.c より古い (source-3.c が更新されている) ので、cc -c source-3.c を実行 ($< には現在のターゲットである source-3.cが入っている)
  • source-3.o が更新されたので、cc -o program ... で program を作成
ただしこれでは *.c と program.h の依存関係が示されていない。そこで
.c.o: program.h
cc -c $<
とすると、source-1.o は source-1.c と program.h から作成されることを表すことができる。

もう少し読みやすくするためにマクロというものを使おう。マクロは変数のようなもので、
MACRO = value
で代入し、$(MACRO) や ${MACRO} で値を参照することができる。目的のファイルは program で、オブジェクトファイルは 3つの *.o でなので、
TARGET = program
OBJS = source-1.o source-2.o source-3.o
と書ける。また、
CC = cc
Cコンパイラ名もマクロで定義しておこう。このように抽象化しておくと cc の代わりに gcc を使いたくなった場合でも、簡単に変更が可能である (FreeBSD や Linux では cc=gcc だが、Solaris などの cc は商用のコンパイラである)。program は OBJS に依存するので
$(TARGET): $(OBJS)
$(CC) -o $@ $(OBJS)
と書ける。$@ は現在のターゲット名が代入されている。さらに clean というターゲットを作成し、いつでも作業途中の全ファイルを消せるようにしよう。

まとめると以下のような Makefile になる。
TARGET = program
OBJS = source-1.o source-2.o source-3.o
CC = cc

.SUFFIXES : .c .o

$(TARGET): $(OBJS)
$(CC) -o $@ $(OBJS)
.c.o: program.h
$(CC) -c $<
clean:
rm -f $(TARGET) $(OBJS)
以上で、
  • make とタイプすると、実行ファイル program を作成することができる。
  • 一部のファイルを更新すると、必要な部分だけを再コンパイルしてくれる。
  • make clean とすることで、program と *.o を削除する。
という Makefile が完成した。

マクロは make の引数で指定することもできる。
% make CC=gcc
とすると、$(CC) の部分が gcc に置き換わって gcc でコンパイルされる。

なお、make でよく使われるルールはデフォルトルールとして、あらかじめ決まっている。FreeBSD では /usr/share/mk/sys.mk がデフォルトルールとして読み込まれる。実は
CC = cc
.SUFFIXES : .c .o
はデフォルトルールとして定義されているので、先にあげた Makefile では この部分を省略してもよい。

make 実行時は、tee コマンドを併用すると便利。

make してエラー(コンパイラのエラーなどではなく、make 自体のエラー)が出た場合、gmake (GNU make) を使うと うまくいく場合がある。なお、Linux では GNU make が make となっている。

make は奥が深く、とてもここで説明しきれるものではない。詳しく知りたい場合は書籍を購入してほしい。
>> OSオンラインマニュアル(man) Linux make(1)
>> OSオンラインマニュアル(man) FreeBSD make(1)

MAKEDEV デバイスファイルを作成する。FreeBSDのみ?

デバイスファイルが /dev/ に存在しない場合、
# cd /dev; ./MAKEDEV デバイス名
などとして、デバイスファイルを作成する。

どのようなデバイスがあるかは MAKEDEV の中身を見るとわかる。MAKEDEV は /dev/MAKEDEV に置いてあるスクリプト。普通パスは通っていないので注意。

man オンラインマニュアルを表示する

UNIX では、基本的に全てのコマンドにオンラインマニュアルが用意されている。
% man コマンド名
とすることで、そのコマンドの説明を見ることができる。例えば ls コマンドのマニュアルを読みたければ
% man ls
とすればいい。また、コマンド名以外にも、システムコールやライブラリ、設定ファイルなどのマニュアルもある。これらは、セクションごとに分けられており、
1 コマンド (ls、cat、kterm など)
2 システムコール (C言語の関数。open、fork など)
3 ライブラリ関数 (C言語の関数。printf、fopen、Tck/Tk、Xlib などの関数群)
4 デバイス・デバイスドライバ
5 ファイルフォーマット (uuencodeなどのファイル形式、hostsなどの書式)
6 ゲーム
7 その他 (環境変数の説明、groff の書式など)
8 システム管理 (各種デーモン、sendmail、mount*など)
9 新しく追加されたマニュアル(Tkなど?)
となっている(これは FreeBSD の場合。OS によってセクション構成が違う場合がある)。

セクション番号を指定するには、
% man セクション名 マニュアル名
とする。例えば ls はコマンドなので、
% man 1 ls
また、fopen はライブラリ関数なので
% man 3 fopen
とすればよい。なお、SystemV 系 UNIX では、マニュアルのセクションを指定する場合、
% man -s 3 fopen
と、-s オプションを付ける必要がある。

ただし、セクション名を省略すると、セクションを1から順に探していって、最初に見付かったマニュアルを表示する。そのため、
% man 1 ls
% man 3 fopen
は、どちらもセクション番号を省略して
% man ls
% man fopen
としてもよい。しかし、異なるセクションに同じ名前のマニュアルが用意されている場合がある。例えば printf は、コマンドの printf (セクション1)、Cのライブラリの printf (セクション3) の
2種類があるので、セクションを指定せず
% man printf
とすると、セクション1の printf コマンドのマニュアルが表示される。C の printf 関数のマニュアルを見るには、
% man 3 printf
とセクション名を明示しなければならない。他のセクションに同名のマニュアルがあるかどうかは、man -aw で調べるとよい。例えば、
% man -aw crontab
/usr/share/man/man1/crontab.1.gz
/usr/share/man/man5/crontab.5.gz
とすると、crontab にはセクション1 (crontab コマンドの説明) とセクション5 (cron の設定ファイルの書式) があることがわかる。

-a 名前にマッチしたマニュアルを全て表示する
-d デバッグモード。マニュアルを探す過程を表示
-f whatis と同じ機能
-k apropos と同じ機能
-w 表示するマニュアルのフルパスを表示
-M マニュアルを検索するパスを指定

man から呼ばれるページャ (more や less) を変更したい場合、環境変数 PAGER で設定できる。当ページ管理人としては、やはり less (FreeBSD なら jless) をお勧めする。

オンラインマニュアルをファイルにリダイレクトしてエディタで見た場合、コントロールコードが含まれているのでうまく表示されない。マニュアルをテキストに変換するには col を使う。

オンラインマニュアルを PostScript ファイルにするには、
% gzcat /usr/share/man/man1/ls.1.gz | groff -man > ls.ps
とすればよい。

FreeBSD・NetBSD・Solaris・Linux などは、日本語マニュアルが用意されている。jman の項を参照。

GNU の多くのコマンドは man ではなく info に詳細な情報が記載されている。man の方は手抜きか、ろくにメンテナンスされていないケースが多い。
>> OSオンラインマニュアル(man) FreeBSD man(1)
>> OSオンラインマニュアル(man) Solaris10 man(1)
>> OSオンラインマニュアル(man) Linux man(7)
>> OSオンラインマニュアル(man) Linux man(1)

manpath man が参照するディレクトリを表示

つまり環境変数 MANPATH を表示するのと同じ。

maplay MPEG AUDIO プレイヤー

Layer3には未対応

maze 迷路を作る

mbadblocks 

mbmon PC のマザーボード監視ツール (ハードウェアモニタツール)

mbmon は PC マシン (PC/AT 互換機) の温度・ファン回転数・電圧などを表示するツールである。X 版として xmbmon というコマンドも用意されており、こちらにはグラフ描画機能がある。

全てのハードウエアモニタチップに対応しているわけではないので、まず自分のマシンで使用可能かを試してみよう。デバッグモードで mbmon を実行して、
% mbmon -d
Using SMBus access method[VIA8233/A(KT266/KT333)]!!
* Asus Chip, ASB100 found.

% mbmon -d
Using VIA686 HWM directly!!
* VIA Chip VT82C686A/B found.
などと出力されれば、チップセットに対応しているということ。エラー表示が出たら、未対応ということ。

実行すると、以下のような情報を 5秒おきに表示する。
% mbmon
Temp.= 33.8, 26.9, 20.7; Rot.= 4963, 0, 0
Vcore = 1.66, 3.33; Volt. = 3.45, 5.05, 11.95, 0.00, 0.00

Temp は温度で、単位は摂氏。
Rot はファン回転数で、単位は「回/分」(=rpm)。
Vcore は CPU の電圧で、単位は V (ボルト)。
Volt はマザーボードに供給される電圧で、単位は V (ボルト)。

上記の例では、
  • 温度は 3つ計測しており、それぞれ 33.8℃・26.9℃・20.7℃ (それぞれがどこの温度なのかはマザーボードに依存する。どれかが CPU の温度で、どれかがマザーボードの温度と思われる)。
  • ファンは 1つしかなく、回転数は 4963rpm。
  • CPU 電圧はコア電圧が 1.66V で、I/O 電圧が 3.33V。
  • 電源ユニットが供給する 3.3V・5V・12V の電圧は、実際には 3.45V・5.05V・11.95V である。
…ということらしいが、当ページ管理人はハードウェアに詳しくないのでよくわからない。

出力形式はオプションで指定できるが、mbmon -h を参照してほしい。

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

Norton Command というツールのクローンらしい。

md5 ファイルの文字列のメッセージダイジェスト (チェックサム) を求める

MD5 は「一方向ハッシュ関数」や「メッセージ要約関数」と呼ばれ、X を加工して Y を求めるのは簡単だが、Y を元に加工される前の X を求めたり、同じ Y になる X' を求めることは難しい。そのため、パスワードの保存やチェックサム代わりとして使われることが多い。

ファイルの MD5 値を求める。
% md5 file.txt
MD5 (file.txt) = a17ab27909dbb125bdabcd25ca19412c
-s文字列 文字列のチェックサムを求める
% md5 -sabc (abcのチェックサムを求める)
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72

md5 コマンドは FreeBSD では標準で含まれているが、他の UNIX 系 OS では md5sum というコマンド名の場合もある。openssl コマンドでもメッセージダイジェストを生成できる。
>> OSオンラインマニュアル(man) FreeBSD md5(1)

md5sum ファイルや文字列のメッセージダイジェスト (チェックサム) を求める

GNU が配布している textutils に含まれている。動作は md5 と全く同じ。
% echo abc | md5sum (abc のチェックサムを求める)

FreeBSD の場合は md5 コマンドを使うとよい。また、openssl コマンドでもメッセージダイジェストを生成できる。
>> OSオンラインマニュアル(man) Linux md5sum(1)

mesg 他ユーザからのメッセージの表示の許可/不許可を設定

他ユーザから talk・write・wall を受けると、メッセージが表示されて画面表示が崩れるのが嫌だったり、talk や write 自体を受けたくないときは mesg で指定できる。

% mesg y
⇒ 他ユーザからの talk・write を許可する
% mesg n
⇒ 他ユーザからの talk・write を禁止する

mesg コマンドは、端末ごとに設定することができる。いくつかの kterm では mesg n として、一つの kterm だけ mesg y としておくと、talk や write のメッセージが、その kterm 上だけに表示される。

mew 高機能メーラー。

emacs/mule 上で動く elisp プログラムと、下請けプログラム (im) を組み合わせて使用する。emacs/mule 上から M-x mew で起動するので、mew というコマンドはない。詳しくは http://www.mew.org/index-j.html を参照。詳細な日本語のマニュアル・FAQ・メーリングリストがある。

Summary モードでの基本操作は以下の通り。
i 新たに到着したメールを取り込む。
n 次のメッセージに移動
p 前のメッセージに移動
d メッセージに削除マークを付ける
x 削除マークを付けたメールを削除する (実際は trash ディレクトリに移動。本当に削除する場合はコマンドラインで imrm コマンドを使う)
a 現在のメッセージに返事を書く。引用は行われない。
A 現在のメッセージに返事を書く。引用が行われる。
f 現在のメッセージを転送する。
w メールを送る。
O メッセージの通し番号を再割り付けする。
g フォルダを移動する。
C-c C-l 化けたメッセージを直せるかも。

mkdir 新しいディレクトリを作る

カレントディレクトリに新しいディレクトリ newdir を作成したいときは、
% mkdir newdir
とする。
% mkdir newdir1 newdir2
% mkdir /foo/bar/newdir1 ../../newdir2
などとすれば複数のディレクトリを同時に作成することができる。

-m 作るディレクトリのパーミッションを指定する。
-m で指定したパーミッションに、umask の値を合わせたものが実際のパーミッションとなる。
-p 再帰的にディレクトリを作成する。
newdir1 というディレクトリが存在しない状態で
% mkdir newdir1/newdir2
とするとエラーになるが、-p オプションを付けて
% mkdir -p newdir1/newdir2
とすると、ディレクトリ newdir1 を新規作成し、その下にディレクトリ newdir2 を新規作成する。
>> OSオンラインマニュアル(man) Solaris10 mkdir(1)
>> OSオンラインマニュアル(man) FreeBSD mkdir(1)
>> OSオンラインマニュアル(man) Linux mkdir(1)
>> OSオンラインマニュアル(man) Linux mkdir(2)

mkfile サイズを指定したファイル生成 (ファイル作成)

指定したサイズのゼロ埋めファイルを生成する。

% mkfile 5 file.dat
⇒ 5 バイトのファイルを生成
% mkfile 10k file.dat
⇒ 10KB のファイルを生成
% mkfile 200m file.dat
⇒ 200MB のファイルを生成
% mkfile 2g file.dat
⇒ 2GB のファイルを生成 (g に対応したのはおそらく Solaris9。それ以前の Solaris では 2048m とすること)

-n オプションを指定すると、穴あきファイルを生成する。
% mkfile -n 4m file.dat
⇒ みかけは 4MB だが、実際には数十KB の容量しかない

mkfile コマンドは Solaris にしか存在しない。他の OS では dd コマンドや yes + head を使う。
>> OSオンラインマニュアル(man) Solaris10 mkfile(1m)

mkfontdir X のフォントのインデックスファイルを作成

*.bdf や *.pcf などのファイルを置いてあるディレクトリに移動し、
% mkfontdir
とすると、カレントディレクトリに fonts.dir というファイルが作成される。fonts.dir の中身は、
エントリ数
フォントファイル名1 対応するフォント名1
フォントファイル名2 対応するフォント名2
フォントファイル名3 対応するフォント名3
...
となっている。(FreeBSD なら) /usr/X11R6/lib/X11/fonts/misc/fonts.dir などを見てみると意味はすぐわかるだろう。

more ファイル表示プログラム (ページャ)

あるコマンドの実行結果や、ファイルの内容を見たいとき、1画面に収まりきらずスクロールしてしまって最初の部分が見えないことがある。そういう場合、
% ls -l | more

% more file.txt
などとすることでゆっくり見ることができる。

一般的な UNIX では、more は先頭に戻ったり 1 行前に戻るなどのバックスクロール機能を持たないが、FreeBSD や HP-UX の more は機能拡張されており、バックスクロールが可能である。

しかし more の高機能版である less というコマンドがあるので、今となっては more を使う意味はない。ぜひ less を使ってほしい。なお FreeBSD の more は日本語を表示できない。jless (ja-less) を使うこと。
>> OSオンラインマニュアル(man) Linux more(1)
>> OSオンラインマニュアル(man) Solaris10 more(1)

mosaic Web ブラウザ

Netscape Navigator の前身で、Web ブラウザのさきがけでもあるが、今となっては骨董品である。

mount ファイルシステムをマウントする

引数なしで実行すると、現在のマウント状況を表示する。
% mount
/dev/ad0s1a on / (ufs, local, soft-updates)
devfs on /dev (devfs, local)
procfs on /proc (procfs, local)
linprocfs on /usr/compat/linux/proc (linprocfs, local)

新たなファイルシステムをマウントする際の基本的な書式は以下の通り。
% mount デバイス名 マウントポイント
引数なしで実行すると現在のマウント状況を表示する。デバイス名は /dev 以下にあるもの。マウントポイントとは「どのディレクトリにアクセスしたらそのファイルシステムが参照できるか」を指定するもの。例えば
% mount /dev/hoge /usr/fuga
とすると、/usr/fuga にアクセスすることで /dev/hoge デバイス内のデータを操作できる。マウントポイント (/usr/fuga) はディレクトリで、事前に mkdir で作成しておく必要がある。

-a /etc/fstab に記述されているとおりにマウントする (noauto を除く)
-t ファイルシステムタイプを指定する。
通常の UNIX のファイルシステムは ufs だが、例えば FreeBSD では、CD-ROM のファイルシステムは cd9660、MS-DOS 形式のファイルシステムは msdos、NFS ファイルシステムは nfs、などといくつか種類がある。-t オプションを使ってマウントしたいファイルシステムの種類を指定できる。
% mount -t msdos /dev/fd0 /mnt
⇒ FD を /mnt に MS-DOS 形式でマウントする。
% mount -t cd9660 /dev/wcd0c /cdrom
⇒ FD を /mnt に MS-DOS 形式でマウントする。
mount_msdos、mount_cd9660 など、mount_* というコマンドは mount -t * と同じ動作をする。

/etc/fstabに
/dev/wcd0c /cdrom cd9660 ro,noauto 0 0
などという記述があれば、
% mount -t cd9660 /dev/wcd0c /cdrom

% mount_cd9660 /dev/wcd0c /cdrom
に加えて、
% mount /cdrom
という省略形が使える。

なお、マウントする前には必ずディスクをフォーマットしておかなければならない。UFS ならば disklabel して newfs を実行。DOS フォーマットなら newfs_msdos である。(FreeBSD の場合)
>> OSオンラインマニュアル(man) Linux mount(2)
>> OSオンラインマニュアル(man) Linux mount(8)
>> OSオンラインマニュアル(man) FreeBSD mount(8)
>> OSオンラインマニュアル(man) Solaris10 mount(1M)

mozilla オープンソースのブラウザ

netscape の項を参照のこと。

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

-k フレーム数 先頭部分を指定のフレームだけスキップする
-d フレーム数 指定のフレーム分だけ飛び飛びに再生する
-h 繰り返す回数 各フレームを指定の回数だけ繰り返して再生する
-r サンプリングレート サンプリングレートを変更する。
標準は 44100Hz。1 に近付くほど再生が遅く、音程が低くなる。44100 以上の値を指定することはできない。
-Z ランダム演奏
-@ URL 指定の URL の MPEG AUDIO データを再生する

mtools MS-DOSフォーマットのフロッピー用のツール集

普通フロッピーディスクを扱う場合は mount コマンドでマウント操作をしなければならないが、マウント・アンマウントを繰り返すのは面倒である。mtools を使えば MS-DOS 上でのファイル操作と同じようにフロッピーを扱うことができる。

FreeBSD の標準設定では、フロッピーディスクのデバイス (/dev/fd0) のパーミッションが rw------- となっているので、root になって
# chmod 777 /dev/fd0
とすることで mtools が使えるようになる。

UNIX と MS-DOS のファイルシステムの違いは、ディレクトリの区切りが / と \ ということと、ドライブ名として A: などと指定することがあげられる。

mattrib MS-DOSファイルの属性を変更する
mbadblocks
mcd MS-DOSでのカレントディレクトリを変更する
mcopy MS-DOSとUNIXとのファイルのやりとりをする
mdel MS-DOSファイルを削除する
mdir MS-DOSファイル・ディレクトリを表示する
mformat フロッピーディスクをMS-DOSフォーマットする
mlabel MS-DOSフロッピーのボリュームラベルを変更する
mmd MS-DOSディレクトリを作成する
mmount
mrd MS-DOSディレクトリを削除する
mmove MS-DOSファイル・ディレクトリを移動する
mren MS-DOSファイル・ディレクトリの名前を変更する
mtype MS-DOSファイルの内容を表示する
mtest

mule 多国語エディタ。nemacs の後継エディタとして開発された。

emacs という、とても有名で高機能なエディタがある。しかし emacs 上では日本語が使えなかったので、日本では emacs を日本語化した nemacs というものが長らく使われてきた。しかし、どうせなら日本語以外に韓国語・中国語・ヘブライ語なども使えるようにしよう、ということで製作されたのが mule である。

最新版の mule は emacs-19.34.1 にパッチを当てた形式で配布されいてる。これは mule の最終版であり、今後メンテナンスされることはないだろう。現在では、mule の多国語機能は emacs に統合されており、emacs-20 系列が開発されている。

また、emacs・mule とは別に、xemacs というエディタがある。これは、emacs の開発の遅さ (GNU が開発を行っている) に耐えかねて、別の人が emacs ライクなエディタを作成したものである。特徴は、xemacs 上で画像を表示できたり、フレームに対応したブラウザが動くなど、X 環境での見栄えを重視している点である。ただしその分 emacs に比べて動作が遅い (xemacs に関しての説明は全く自信がない。突っ込み歓迎)。

以上のように、emacs 系エディタはたくさんある。どれを選べばよいか、という指針を考えてみる。
  • nemacs … 現在では使う必要はない。古すぎる。
  • mule … 比較的軽いかもしれない。長らく日本で使われてきた。過去の ~/.emacs などの資産を生かせるが、初めて emacs を使う人はあえて選択する必要はないだろう。現在 mule を使っている人は、不満がないなら使い続けるとよい。
  • emacs … emacs の本流。日本語も問題なく使えるが、~/.emacs で少々設定が必要。
  • xemacs … 見栄え重視で、それなりに速いマシンを持っている人向け。
それぞれ、~/.emacs の書き方などが若干違う。mule の ~/.emacs が emacs でも動くとは思わない方がよいだろう。

emacs の機能は本当にたくさんあるので、ごく一部だけを説明する。重要な機能には(*)マークを付けた。その中でも特に覚えておいた方がよいのは、
  • C-x C-c mule の終了
  • C-x C-s セーブ
  • C-g 実行中のコマンドをキャンセル (とにかくキーが入力できなくなったらこれを連打すること)
である。ほとんどの機能は emacs・xemacs でも使えるはずである。なお、
  • M-x というのは、ESC キーを押して (離したあとに) xキーを押す
  • C-x というのは、CTRL キーを押しながらxキーを押す
  • M-C-s というのは、ESC キーを押して (離したあとに)、CTRL キーを押しながら s キーを押す
という意味である。

オプション
+n(数字) 起動後ファイルの n 行目に移動する
-nw 新たな X のウィンドウを作らず、現在のコンソール上で実行する
-q 設定ファイル (~/.emacs など) を読み込まない
-u user userの設定ファイルを読み込む
-u hoge とすると、起動時の設定ファイルとして ~hoge/.emacs が読み込まれる
-l file コンフィグファイル file を読み込む
-f function LISP の関数を実行する。
例・mule -f c-mode
mule -f rmail(メール)
mule -f gomoku(五目並べ)
カーソル移動
C-a 行頭に移動(*)
C-e 行末に移動(*)
C-n 1行下に移動(*)
C-p 1行上に移動(*)
C-f 1文字前に移動(*)
C-b 1文字後ろに移動(*)
C-v 1画面進む(*)
M-v 1画面戻る(*)
M-< 先頭行に移動(*)
M-> 最終行に移動(*)
C-x C-x マーク位置へ移動、もう一度入力すると元に戻る
C-x = 現在カーソルがどこにあるかを表示
M-x goto-line 指定の行へ移動(*)
マーク
C-@ 現在カーソルのある位置をマーク(*)
C-SPACE 現在カーソルのある位置をマーク(*)
C-x h バッファ全体をマーク
検索
C-s インクリメンタルサーチ(あるいは次検索)(*)
C-s C-s 次検索(*)
C-r 後方インクリメンタルサーチ
M-C-s 正規表現インクリメンタルサーチ
M-C-r 後方正規表現インクリメンタルサーチ
削除・貼り付け
C-d 1文字削除(*)
C-k カーソル位置からその行の行末まで削除(*)
C-w マークした位置からカーソル位置までを削除してキルリングにコピー(*)
M-w マークした位置からカーソル位置までをキルリングにコピー(*)
C-y キルリングの内容を貼り付け(*)
M-y 一つ前のキルリングの内容を貼り付け。
C-y に続けて M-y とすることでキルリングをさかのぼることができる(M-y は C-y の直後に押さないと意味がない)。C-y M-y M-y M-y … と連続してさかのぼることも可能。
C-x C-t カーソルのある行とその上の行を入れ換え

C-o 空行を挿入
C-x u アンドゥ(*)
C-g 実行中のコマンドをキャンセル(*)
C-l 画面を再描画して、カーソルのある行が画面の中心にくるように表示(*)
C-m リターンキーと同じ

C-x r k 矩形領域の切り取り
C-x r y 矩形領域の貼り付け
C-x r t 矩形領域を指定した文字列で置き換え
C-x r o 矩形領域に空白を挿入
C-x r o 矩形領域を空白で置き換え

保存・終了
C-x C-s バッファ内容をファイルに保存(*)
C-x C-w ファイル名を指定してセーブ
C-x C-c muleの終了(*)
C-z サスペンド
バッファ・ウィンドウ
C-x C-f 指定ファイルを編集(*)
C-x C-b 現在のバッファのリストを表示(*)
C-x 0 カレントウィンドウを消去(*)
C-x 1 カレントウィンドウ以外のウィンドウを消去(*)
C-x 2 カレントウィンドウを横に2分割(*)
C-x 3 カレントウィンドウを縦に2分割
C-x o 次ウィンドウに移動(*)
C-x + 全ウィンドウを均等なサイズに変更
C-x ^ カレントウィンドウを拡大(*)
C-x b 編集するバッファを変更(*)
C-x C-b 現在編集中のバッファのリストを表示
C-x C-d ディレクトリを表示
C-x d diredを実行
C-x C-r 新たにファイルを読み込む(リードオンリー)
C-x i ファイル内容を現在位置に挿入
C-x C-x バッファを削除
C-x 4系 他のウィンドウを操作
C-x 4 b 他のウィンドウに指定バッファを表示
C-x 4 f 他のウィンドウでファイルを編集
C-x 4 m 他のウィンドウでメール
C-x 4 r 他のウィンドウにファイルを読み込む(リードオンリー)
C-x 4 d 他のウィンドウでdired
C-x 5系 他のフレームを操作
C-x 5
マクロ
C-x ( マクロの設定を開始
C-x ) マクロの設定の終了
C-x e 設定したマクロを実行
ヘルプ
M-x describe-bindings 現在のキー割り当ての説明
M-x describe-variable emacs変数の説明
M-x describe-function 関数の説明
M-x describe-mode 現在のメジャーモードの説明
漢字変換
C-\ たまごの起動
C-o かんなの起動
C-x SPC マーク位置からカーソル位置まで再変換
その他
C-u n command commandをn回繰り返す。C-u 3 C-n は C-n C-n C-n と同じ
C-x TAB マークした場所からカーソル位置までの行を字下げする
C-^ 記号入力モード
C-x = カーソルの位置を表示
C-x m メールを送信
ESC ! シェルコマンドを実行
C-x l バッファの行数と現在位置を表示
便利なコマンド
M-x goto-line 指定の行に移る(行番号を指定)
M-x tabify マーク位置から現在位置までのスペースをタブに変換
M-x untabify マーク位置から現在位置までのタブをスペースに変換
M-x canna-touroku 新たに単語を登録 (かんな)
M-x replace-string 文字列を置換(*)
M-x replace-regexp 文字列を置換 (正規表現で指定)
M-x rmail メールを読む
モード
M-x fundamental-mode 基本的なメジャーモード
M-x override-mode 上書き/挿入モード (トグル)
M-x auto-fill-mode 自動改行モード。
リターンキーを押したときに、その行が指定の文字数より長かったら、自動的に指定の文字数のところで改行する。任意のカラムで C-x f することで、1行の長さを設定できる。

mv ファイルの移動、リネーム (名前変更)

mv はファイルの移動と、ファイル名の変更という2つの機能を持つ。

% mv file1 file2
⇒ file1 を file2 にリネーム
% mv file1 (file2 ...) dir
⇒ file1 (file2 ...) をディレクトリdirに移動
% mv dir1 dir2
⇒ (dir2 が存在しない場合) dir1 を dir2 にリネーム
% mv dir1 dir2
⇒ (dir2 が存在する場合) dir1 を dir2 の下に移動

なお、DOS とは違って UNIX では メタキャラクタの展開はシェルの役割なので、
% mv *.txt *.txt.bak
などとしても拡張子の一括変換はできない。Linux においては rename コマンドにて
一括リネームが可能である。
Linux 以外の場合は、csh・tcsh なら foreach、sh・bash なら for を使うとよい。

オプション
-i 移動先のファイルが既に存在する場合、上書きしてよいか確認する
-f 強制的に削除を行う。alias mv mv -i としているときに -f オプションを使うと便利
-R 指定ディレクトリ以下のファイルを再帰的に移動

ファイル名のエンコーディングの変換
ファイル名自体のエンコーディングを変換する場合は、convmv コマンドを使うとよい。

>> OSオンラインマニュアル(man) Solaris10 mv(1)
>> OSオンラインマニュアル(man) FreeBSD mv(1)
>> OSオンラインマニュアル(man) Linux mv(1)

mxaudio GUIインタフェースを持ったMPEG AUDIOプレイヤー

mysql MySQL データベースにアクセスするためのコマンド・コマンドラインツール

mysql コマンドは、MySQL データベースにアクセスするためのコマンドである。つまり MySQL のクライアントアプリケーションである。mysql コマンドを使って、コマンドラインよりテーブルの管理や SELECT・INSERT などの SQL 文を実行することができる。


接続
mysql コマンドは、引数なしの場合、
  • 接続先は同じサーバ内の UNIX ドメインソケット (/var/lib/mysql/mysql.sock や /tmp/mysql.sock など)
  • ユーザ名は自分の UNIX ユーザ名
  • パスワードは空
に接続しようとする。

下記のオプションを駆使して頑張って接続してほしい。

-u [ユーザ名] または --user=[ユーザ名]
-h [ホスト名] または --host=[ホスト名]
-p または --password=[パスワード]
-P または --port=[ポート番号]
-d [データベース名] または --database=[データベース名] または [データベース名]

最終的には
mysql>
というプロンプトが出れば OK である。

データベース操作
接続後、デフォルトとするデータベースを選択する。
USE [データベース名]
USE を書けば便利というだけで、書かなくてはならないものではない。一度 USE すれば
SELECT * FROM [データベース名].[テーブル名];

SELECT * FROM [テーブル名];
と短く書ける、というだけの話である。
データベースの一覧を表示
SHOW DATABASES;
データベースを新規作成
CREATE DATABASE [データベース名];
既存データベースの CREATE DATABASE 文を出力する
SHOW CREATE DATABASE [データベース名];

テーブル操作
テーブルの一覧を表示
SHOW TABLES;
→ 現在 USE で選択中のデータベースに含まれるテーブル一覧を表示する。
SHOW TABLES LIKE '%abc%';
→ テーブル名に abc を含むテーブル一覧を表示する。
SHOW TABLES FROM [データベース名];
→ 現在 USE で選択中でない場合でも、FROM [データベース名] で指定可能。
テーブルの詳細情報を表示
SHOW TABLE STATUS
テーブルの作成
CREATE TABLE [テーブル名] (カラム定義) Engine=InnoDB;
→ Engine がよくわからなければ、InnoDB で作っておくこと。
テーブルのコピー
CREATE TABLE [新テーブル名] AS SELECT * FROM [旧テーブル];
→ 旧テーブルと同じテーブルを作成し、データもコピーする。
テーブルのコピー (データなし)
CREATE TABLE [新テーブル名] AS SELECT * FROM [旧テーブル] WHERE 1=0;
→ 旧テーブルと同じテーブルを作成するが、データはコピーしない。
テーブルの削除
DROP TABLE [テーブル名];
テーブルの CREATE 文を表示する
SHOW CREATE TABLE [テーブル名];
テーブル名の変更
ALTER TABLE [旧テーブル名] RENAME TO [新テーブル名]

カラム追加・削除・表示
テーブルのカラム情報を表示
SHOW COLUMNS FROM [テーブル名];
mysql> SHOW COLUMNS FROM mytable;
+-----------------+------------+------+-----+---------+-------+
| Field           | Type       | Null | Key | Default | Extra |
+-----------------+------------+------+-----+---------+-------+
| foo_id          | int(11)    | NO   | PRI | NULL    |       |
| mytext          | mediumtext | NO   |     | NULL    |       |
| display_order   | int(11)    | NO   |     | NULL    |       |
| enable_flag     | tinyint(1) | NO   |     | NULL    |       |
| insert_datetime | datetime   | NO   |     | NULL    |       |
| update_datetime | datetime   | NO   |     | NULL    |       |
+-----------------+------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
なお、DESC、DESCRIPTION、SHOW FIELDS でも同じ。
SHOW FULL COLUMNS FROM [テーブル名];
SHOW COLUMNS に Collation・Privileges を追加したより詳細な情報を表示。
カラムの追加
ALTER TABLE [テーブル名] ADD COLUMN [カラム定義]
→ カラムがテーブルの末尾に追加される
ALTER TABLE [テーブル名] ADD COLUMN ([カラム定義1], [カラム定義2], ...)
→ 複数カラムを同時に追加
ALTER TABLE [テーブル名] ADD COLUMN [カラム定義] FIRST
→ テーブルの先頭に移動
ALTER TABLE [テーブル名] ADD COLUMN [カラム定義] AFTER [既存カラム名]
→ [既存カラム] の後に追加
カラム名の変更 + カラム型・定義の変更
ALTER TABLE [テーブル名] CHANGE [旧カラム名] [新カラム名] [新カラム定義]
カラム名だけを変更したい (カラム定義は変えたくない) 場合であっても、DEFAULT や NOT NULL などのカラム定義は必ず指定しないといけない。現在のカラム定義と異なるものを指定してしまうと
カラム型・定義の変更
ALTER TABLE [テーブル名] MODIFY [カラム名] [新カラム定義]
DEFAULT 句のみの変更
ALTER TABLE [テーブル名] ALTER [カラム名] SET DEFAULT [デフォルト値]
ALTER TABLE [テーブル名] ALTER [カラム名] DROP DEFAULT
→ データ出力が不要なので、MODIFY より速い。
インデックス
インデックスの作成
ALTER TABLE [テーブル名] ADD INDEX [インデックス名] (col1)
ALTER TABLE [テーブル名] ADD INDEX index_name (col1, col2)
→ 複合インデックスの場合
インデックスの削除
ALTER TABLE [テーブル名] DROP INDEX index_name;
ALTER TABLE [テーブル名] ADD UNIQUE (col1);
ALTER TABLE [テーブル名] ADD PRIMARY KEY (col1);
ALTER TABLE [テーブル名] DROP PRIMARY KEY;
インデックスの確認
SHOW INDEX FROM [テーブル名];
または
SELECT table_schema, table_name, index_name, column_name, seq_in_index
FROM information_schema.statistics
WHERE table_schema = 'mydb' AND table_name = 'mytable'
システム変数など
システム変数を表示する。
SHOW VARIABLES;
→ 全変数を表示。
SHOW VARIABLES like '%abc%';
→ 変数名で絞ることもできる。
(★GLOBAL と SESSION について要追記)

SHOW STATUS

プロセス
プロセスの一覧を確認
SHOW PROCESSLIST
SQL 省略なしでプロセスの一覧を確認 (長くなるので \G をおすすめする)
SHOW FULL PROCESSLIST
重い SQL を確認したら、KILL コマンドでプロセスを殺す。

型 (整数型)
整数型 TINYINT 1バイト -128〜127
整数型 TINYINT UNSIGNED 1バイト 0〜255
整数型 SMALLINT 2バイト -32768〜32767
整数型 SMALLINT UNSIGNED 2バイト 0〜65535
整数型 MEDIUMINT 3バイト -8388608〜8388607
整数型 INT 4バイト -2147483648〜2147483647
整数型 BIGINT 8バイト -9223372036854775808〜9223372036854775807

TINYINT(1) や INT(2) といった書き方ができるが、これは領域長を示すものではなく、単なる表示幅である。TINYINT はあくまで 1バイトであるし、INT はあくまで 4バイトである。

表示幅とは何かと言うと、ゼロパディングをする ZEROFILL を設定したとき、この表示幅が使われる。実体としては単なる TINYINT なので、あくまで表示の際にゼロパディングしているだけである。
mysql> CREATE TABLE mytable (
  col1 TINYINT(2) ZEROFILL,
  col2 TINYINT(10) ZEROFILL
);
mysql> insert into mytable values (1,2);
Query OK, 1 row affected (0.01 sec)

mysql> select * from mytable;
+------+------------+
| col1 | col2       |
+------+------------+
|   01 | 0000000002 |
+------+------------+
ただ、SELECT col1+1, col2+1 としただけでゼロパディングがなされないような中途半端なものを本当に使うべきなのかよく考えた方がよいと思う。

型 (固定小数型)
DECIMAL(N,M)
小数部 M 桁を含む、全体で N 桁の数を保持できる。DECIMAL(5,2) であれば、-999.99〜999.99 となる。
DECIMAL(N)
桁数 N 桁の整数を保持できる。DECIMAL(3) であれば、-999〜999 となる。DECIMAL(N) は DECIMAL(N,0) と同じ。
DECIMAL(N,M) UNSIGNED
マイナスが使えなくなる以外は DECIMAL(N,M) と同じ。

N の最大は 65 である。よって、DECIMAL(65)、DECIMAL(65,5)、DECIMAL(65,45) などが可能である(それぞれ、整数部65桁・小数部なし、整数部60桁・小数部5桁、整数部20桁・小数部45桁)。

MySQL では NUMERIC は DECIMAL の別名である。

型 (日付)
DATE
年月日を保持する。範囲は '1000-01-01' から '9999-12-31'。
データサイズは、3バイト。
DATETIME
年月日時分秒を保持する。範囲は '1000-01-01 00:00:00' から '9999-12-31 23:59:59'。ミリ秒・マイクロ秒は扱えない。
データサイズは、MySQL 5.6.3 までは 8バイト。MySQL 5.6.4 以降は 5バイト + 小数秒サイズ。
TIMESTAMP
年月日時分秒に加え、マイクロ秒まで保持する。範囲は '1970-01-01 00:00:01' から '2038-01-19 03:14:07'。
MySQL 5.6.3 までは、DEFAULT current_timestamp を指定できるのは TIMESTAMP だけであったが、MySQL 5.6.4 以降は TIMESTAMP も DATETIME も指定できるようになった。
データサイズは、MySQL 5.6.3 までは 4バイト。MySQL 5.6.4 以降は 4バイト + 小数秒サイズ。

上記の、小数秒サイズとは何かと言うと、下記のように必要な精度によって変わる。
小数秒精度 必要なサイズ
0 0バイト
1〜2桁 1バイト
3〜4桁 2バイト
5〜6桁 3 バイト

要はこういうことだ。
MySQL 5.6.3以前 + DATETIME 8バイト
MySQL 5.6.4以降 + DATETIME(0) 5バイト
MySQL 5.6.4以降 + DATETIME(1) または DATETIME(2) 6バイト
MySQL 5.6.4以降 + DATETIME(3) または DATETIME(4) 7バイト
MySQL 5.6.4以降 + DATETIME(5) または DATETIME(6) 8バイト

他にも YEAR 型・TIME 型がある。

型 (文字列型)
CHAR
長さは 0〜255。例えば CHAR(5) とした上で 'abcd' という値を入れると、SELECT 時には 'abcd ' と末尾に空白が付いた形で受け取ることになる。
VARCAHR(N)
N は文字数。最大領域は 65535バイトだが、UTF-8 だと 1文字3バイトだったり、最近は 1文字4バイト(?)だったり、管理用の領域があったりして、UTF-8 の場合は最大 VARCHAR(21844) らしい。
型 (BLOB)
TINYBLOB
BLOB
MEDIUMBLOB
LONGBLOB

型 (TEXT)
TINYTEXT
TEXT
MEDIUMTEXT
LONGTEXT

SELECT
SELECT * FROM TABLE;
SELECT 'abc', 123, now()
→ MySQL は FROM なしでも可能。Oracle は必須なので FROM dual とする。

ORDER BY
SELECT * FROM TABLE ORDER BY col1;
→ col1 の昇順でソートする。
SELECT * FROM TABLE ORDER BY col1 ASC;
→ ASC を明示的につけても同じ挙動 (ASC=ascending)。
SELECT * FROM TABLE ORDER BY col1 DESC;
→ DESC とすると降順 (DESC=Descending)。
SELECT * FROM TABLE ORDER BY col1, col2;
→ col1 の昇順でソートし、col1 が同じ値の場合は col2 の昇順でソートする。
SELECT * FROM TABLE ORDER BY col1 DESC, col2 ASC;
→ col1 は降順、col2 は昇順とすることもできる。
SELECT * FROM TABLE ORDER BY (CASE WHEN col1=9999 then 0 else col1 END)
→ CASE 文でより複雑な書き方もできる。この例では col1 の 9999 は特殊値なので 0 と同じに扱っている)
SELECT * FROM TABLE ORDER BY (CASE WHEN col1=9999 then 0 else col1 END) DESC, col2 ASC
→ CASE 文と、カラムをつなげることもできる。
昇順・降順とは、についてはいつか書く (照合順序・Collation)。

WHERE
SELECT * FROM TABLE WHERE col1 = 'X';
SELECT * FROM TABLE WHERE col1 = 'X' AND col2 = 'Y';
SELECT * FROM TABLE WHERE val1 < 100 OR val2 > 200;
SELECT * FROM TABLE WHERE val1 <= 100 OR val2 >= 200;
SELECT * FROM TABLE WHERE val1 LIKE '%abc';
→ abc で終わる
SELECT * FROM TABLE WHERE val1 LIKE '%abc%';
→ abc が含まれる
SELECT * FROM TABLE WHERE val1 LIKE 'abc%';
→ abc で始まる
SELECT * FROM TABLE WHERE val1 LIKE 'a_';
→ a のあとに任意の 1文字が続く
SELECT * FROM TABLE WHERE val1 BETWEEN 100 AND 200;
→ 100 <= val1 AND val1 <= 200 と同じ
SELECT * FROM TABLE WHERE val1 IN (1,2,3,4);
SELECT * FROM TABLE WHERE val1 IN (SELECT xxx FROM yyy)
SELECT * FROM TABLE WHERE val1 NOT IN (SELECT xxx FROM yyy)

GROUP BY
SELECT col1, COUNT(*) FROM TABLE GROUP BY col1;
SELECT col1, MAX(col2) FROM TABLE GROUP BY col1;
SELECT col1, COUNT(*) FROM TABLE GROUP BY col1 HAVING COUNT(*)>4;

DISTINCT
SELECT DISTINCT col1 FROM TABLE;
→ col1 の重複を取り除いて取得
SELECT DISTINCT col2, col3 FROM TABLE;
→ 複数カラムに対して distinct
SELECT COUNT(DISTINCT col1) FROM TABLE;
→ col1 の種類数を数える (重複除外した上でのカウント)

SELECT の LIMIT
SELECT * FROM mytable LIMIT 10;
→ 先頭10行のみ出力
SELECT * FROM mytable LIMIT 5, 10;
→ 先頭6行目 (0行目からカウント) を先頭に 10行分を出力 (つまり 6〜15行目)

SELECT の、おおむね全部のせ
SQL の書き方には順序が決められている。以下、SELECT の主要な構文を載せてみたので参考にしてほしい。
SELECT DISTINCT col1
FROM mytable
WHERE col2=1
GROUP BY col3, col4
HAVING count(*)>1
ORDER BY col5 asc, col6 desc
LIMIT 10, 5;
ちなみに、評価順は下記となる。
1. FROM mytable (mytable から)
2. WHERE col2=1 (col2=1 なレコードを抽出し)
3. GROUP BY col3, col4 (col3 と col4 で集約し)
4. HAVING count(*)>1 (col3 と col4 で集約した結果、2行以上あるものを選び)
5. SELECT MAX(col1) (co3 と col4 で集約した結果それぞれで最大の col1 を選び)
6. ORDER BY col3 ASC, col4 DESC (col3 の昇順、col3 が同じなら col4 の降順でソートし)
7. LIMIT 10, 5 (9行目から 5行を出力する)

文字列関数
文字列結合 (CONCAT)
SELECT CONCAT(123, ' a ',NOW());
→ || で文字列結合したいなら PIPES_AS_CONCAT 変数の設定が必要

NULL
SELECT * FROM mytable WHERE col IS NULL;
→ NULL 確認は = NULL ではなく IS NULL で。
SELECT * FROM mytable WHERE col IS NOT NULL;
→ NULL じゃない場合は、IS NOT NULL。
SELECT IFNULL(col, 'NULLでした') FROM mytable;
→ col が NULL なら、"NULLでした" に置換。NULL でないならそのまま。
SELECT * FROM mytable WHERE IFNULL(col, 0) <10;
→ col が NULL なら 0 に置換した上で、10 と比較。IFNULL なしだと unknown になり、ヒットしない。

正規表現
SELECT * FROM TABLE WHERE val1 REGEXP 'abc';
→ abc が含まれる
SELECT * FROM TABLE WHERE val1 REGEXP 'abc$';
→ abc で終わる
SELECT * FROM TABLE WHERE val1 REGEXP '^abc';
→ abc で始まる
SELECT * FROM TABLE WHERE val1 REGEXP '^abc$';
→ abc に完全に一致する
SELECT * FROM TABLE WHERE val1 REGEXP '^[0-9][0-9][0-9][0-9]/[0-9][0-9]?/[0-9][0-9]?$';
→ 2017/04/01 でも 2017/4/1 でもひっかかるように

コメント
MySQL では「#」「--」「/* 〜 */」の 3種類のコメントを受け付ける。「--」の後には半角スペース・タブ・改行が必要であることに注意。
SELECT 1; # ここはコメント
SELECT 1; -- ここはコメント
SELECT 1; /* ここはコメント */
SELECT 1; /* 複数行の
コメント */
ただし「/*! 〜 */」は MySQL には解釈される。
SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ...
は MySQL にとっては
SELECT STRAIGHT_JOIN col1 FROM table1,table2 WHERE ...
と同じ。



INSERT
テーブルに 1行追加する。
INSERT INTO [テーブル名] VALUES (1, 'A', NOW());
省略せずに書くならば、下記のようにカラム名を列挙する。
INSERT INTO [テーブル名] (カラム1, カラム2, カラム3) VALUES (1, 'A', NOW());
SHOW COLUMNS の並び順通りに書く場合、カラム名の列挙は省略できる。

テーブルに複数行を追加する。
INSERT INTO [テーブル名] VALUES
(2, 'C', NOW()),
(3, 'E', NOW()),
(4, 'G', NOW());
INSERT 時にプライマリキーの重複が発生した場合、UPDATE で更新する。
INSERT INTO [テーブル名] (col1, col2) VALUES (1, 'a')
ON DUPLICATE KEY UPDATE col2='a';
→ col1 が主キーでそれがかぶった場合、UPDATE col2='a' WHERE col1=1 的な処理を行う。
複数行 INSERT でキー重複した場合、"VALUES (カラム名)" という書き方が便利。
INSERT INTO [テーブル名] (col1, col2) VALUES (1, 'a'), (2, 'b')
ON DUPLICATE KEY UPDATE col2= VALUES (col2);
→ 行に応じて UPDATE SET col2='a' になったり、UPDATE SET col2='b' になったりする。
★update set col=default、update set col2=default(col1) という書き方もある。

DELETE
全レコード削除
DELETE FROM [テーブル名];
→ 全レコード削除。TRUNCATE の使用も検討すること。ロールバック可能。
特定レコード削除
DELETE FROM [テーブル名] WHERE col1 = 1;
最大N行削除
DELETE FROM [テーブル名] LIMIT 100;
→ DELETE の LIMIT には最大件数しか書けない

UPDATE
全行更新
UPDATE [テーブル名] SET col1 = 1;
UPDATE [テーブル名] SET col1 = NULL;
条件指定
UPDATE [テーブル名] SET col1 = 1 WHERE col2 > 100
最大N行更新
UPDATE [テーブル名] SET col1 = 1 WHERE col1 IS NULL LIMIT 100;
→ UPDATE の LIMIT には最大件数しか書けない
別テーブルから値を転記
UPDATE items, month SET items.price = month.price
WHERE items.id = month.id;
上記の書き方は、MySQL では 「複数テーブル構文」と呼ぶらしい。ちなみに Oracle では下記のようにするが、A は MySQL でも成功、B は失敗した。
-- A: 1カラム更新
UPDATE items SET price = (SELECT price FROM month WHERE id=items.id);
-- B: 複数カラム更新
UPDATE items SET (price_tax, price_notax) = (SELECT price_tax, price_notax FROM month WHERE id=items.id);

TRUNCATE
TRUNCATE TABLE [テーブル名]
全レコード削除。ロールバック不可。ちなみに PostgreSQL では TRUNCATE もロールバックできたりする。

explain
quit
終了

関数: 日時・日付・時間・時刻の取得 2017/06/07 作成
NOW 関数: 現在の日時を返す。
NOW 関数は現在の日時 (年月日時分秒) を返す。
mysql> select NOW();
2017-06-04 14:32:02

NOW() が返すのはステートメントの開始時刻であることに注意。以下のように SLEEP を挟んで 2回 NOW() を実行しても、同じ日時が返ってくる。
mysql> select NOW(), SLEEP(5), NOW()\G
2017-06-04 14:32:02
2017-06-04 14:32:02
なお、LOCALTIME(), LOCALTIME, LOCALTIMESTAMP, LOCALTIMESTAMP(), CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP はいずれも NOW() の別名である。

SYSDATE 関数: 現在の日時を返す。
SYSDATE 関数は、現在の日時 (年月日時分秒) を返す。NOW 関数のようにステートメントの開始時刻ではなく、SYSDATE 関数が実行されたその瞬間の日時を返す。よって、SLEEP を挟んでも下記のようにその時点での時刻を取得できる。
mysql> select SYSDATE(), SLEEP(5), SYSDATE()\G
2017-06-04 14:32:02
2017-06-04 14:32:07

CURDATE 関数: 現在の日付を返す。
CURDATE 関数は現在の日付を返す。
mysql> select CURDATE();
2017-06-04

CURRENT_DATE() と CURRENT_DATE は CURDATE 関数の別名である。

UTC_TIMESTAMP 関数: UTC での現在の日時を返す。
mysql> select UTC_TIMESTAMP();
2017-06-04 05:32:02
UTC_DATE 関数: UTC での現在の日付を返す。
mysql> select UTC_DATE();
2017-06-04
UTC_TIME 関数: UTC での現在の時間を返す。
mysql> select UTC_TIME();
05:32:02
UNIX_TIMESTAMP 関数: UNIX epoch の秒数を返す。
UNIX epoch の秒数 (1970-01-01 00:00:00 からの経過秒数) を返す。
mysql> select UNIX_TIMESTAMP();
1496815435
datetime・timestamp 型のカラムに対して UNIX epoch に変換することもできる。
mysql> select UNIX_TIMESTAMP(last_modified) from mytable;

関数: 日時・日付・時間・時刻の加工 2017/06/07 作成
YEAR 関数: 年の部分を返す
MONTH 関数: 月の部分を返す
DAYOFMONTH 関数: 日の部分を返す
mysql> select YEAR(NOW()), MONTH(NOW()), DAYOFMONTH(NOW())\G
2017
7
4
→ 2017年7月4日
HOUR 関数: 時間の部分を返す
MINUTE 関数: 分の部分を返す
SECOND 関数: 秒の部分を返す
mysql> select HOUR(NOW()), MINUTE(NOW()), SECOND(NOW())\G
11
8
57
→ 11時8分57秒

Tips1. mysql コマンドプロンプトでの入力のクリア
mysql> seleeeect col1
->
→ select のつづりを間違えたことに気づいたが、すでに Enter を押してしまっている。
こういうとき Ctrl-c で mysql コマンド自体を終わらせたり、セミコロンで無理やりエラーにしてしまったり、としている人もいるかと思うのだが、\c で入力バッファのクリアができる。
mysql> seleeeect col1
-> \c
→ 入力途中のものはなかったことになる
mysql> seleeeect col1
-> aaaa\c
→ 途中まで入力した後に \c でもよい。
実は mysql コマンド起動直後にもそう書いてある。
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
ただし、
mysql> seleeeect "aaa
"> \c
→ "" 内部なのでクリアできない
などとクォート内部だったりするとクリアできない ("" を閉じてから \c しないといけない)。

MySQL 5.7.1 以降なら、Ctrl-c でもバッファクリアできる (それ以前のバージョンでは mysql コマンドが終了してしまう)。

Tips2. \G
SELECT 文などの行末を ; ではなく \G で終わらせると、表形式ではなく、縦に並べてくれる。

通常の SELECT:
mysql> select * from t;
+------+------+
| a0   | a1   |
+------+------+
|    0 |    0 |
|  100 |  200 |
+------+------+
2 rows in set (0.00 sec)
\G な SELECT:
mysql> select * from t\G
*************************** 1. row ***************************
a0: 0
a1: 0
*************************** 2. row ***************************
a0: 100
a1: 200
2 rows in set (0.05 sec)

通常の SHOW TABLES
mysql> show tables;
+------------------+
| Tables_in_mytest |
+-----------------+|
| table1           |
| table2           |
| table3           |
+------------------+
3 rows in set (0.02 sec)
\G な SHOW TABLES
mysql> show tables\G
*************************** 1. row ***************************
Tables_in_mytest: t
*************************** 2. row ***************************
Tables_in_mytest: t2
*************************** 3. row ***************************
Tables_in_mytest: t3
3 rows in set (0.00 sec)

通常の SHOW COLUMNS (DESC)
mysql> desc t;
+-------+------------+------+-----+---------+-------+
| Field | Type       | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| a0    | tinyint(4) | YES  |     | NULL    |       |
| a1    | tinyint(1) | YES  |     | NULL    |       |
+-------+------------+------+-----+---------+-------+
2 rows in set (0.27 sec)
\G な SHOW COLUMNS (DESC)
mysql> desc t\G
*************************** 1. row ***************************
  Field: a0
   Type: tinyint(4)
   Null: YES
    Key:
Default: NULL
  Extra:
*************************** 2. row ***************************
  Field: a1
   Type: tinyint(1)
   Null: YES
    Key:
Default: NULL
  Extra:

ncftp 高機能 ftp クライアント

「ニックエフティーピー」と呼ぶらしい。

FreeBSD の ftp コマンドはかなり高機能で、tcsh 風のファイル・ディレクトリ補完機能が備わっている。まずは標準の ftp コマンドを使ってみて、それでも不満なら ncftp を使うとよい。

nemacs 日本語を扱える emacs

既に nemacs の開発は終了し、mule に引き継がれた。そして mule の開発も終了し、本家 emacs に統合されている。

netpbm 画像処理プログラム

netpbm は各種画像コンバータの総称で、netpbm というコマンドはない。netpbm は以下のバイナリで構成されている。AAAtoBBB というコマンドは、AAA 形式の画像ファイルを指定すれば、標準出力に BBB 形式の画像ファイルを書き出してくれる。例えば
% pgmtopbm < hoge.pgm > hoge.pbm
などと実行する。

netpbm に含まれるコマンドは以下のとおり。
anytopnm、asciitopgm、atktopbm、bioradtopgm、bmptoppm、brushtopbm、cmuwmtopbm、fitstopnm、fstopgm、g3topbm、gemtopbm、giftopnm、gouldtoppm、hipstopgm、hpcdtoppm、icontopbm、ilbmtoppm、imgtoppm、lispmtopgm、macptopbm、mgrtopbm、mtvtoppm、pbmclean、pbmlife、pbmmake、pbmmask、pbmmerge、pbmpscale、pbmreduce、pbmtext、pbmto10x、pbmto4425、pbmtoascii、pbmtoatk、pbmtobbnbg、pbmtocmuwm、pbmtoepsi、pbmtoepson、pbmtog3、pbmtogem、pbmtogo、pbmtoicon、pbmtolj、pbmtoln03、pbmtolps、pbmtomacp、pbmtomgr、pbmtopgm、pbmtopi3、pbmtopk、pbmtoplot、pbmtoptx、pbmtox10bm、pbmtoxbm、pbmtoybm、pbmtozinc、pbmupc、pcxtoppm、pgmbentley、pgmcrater、pgmedge、pgmenhance、pgmhist、pgmkernel、pgmmerge、pgmnoise、pgmnorm、pgmoil、pgmramp、pgmtexture、pgmtofs、pgmtolispm、pgmtopbm、pgmtoppm、pi1toppm、pi3topbm、picttoppm、pjtoppm、pktopbm、pnmalias、pnmarith、pnmcat、pnmcomp、pnmconvol、pnmcrop、pnmcut、pnmdepth、pnmenlarge、pnmfile、pnmflip、pnmgamma、pnmhistmap、pnmindex、pnminvert、pnmmargin、pnmmerge、pnmnlfilt、pnmnoraw、pnmpad、pnmpaste、pnmrotate、pnmscale、pnmshear、pnmsmooth、pnmtile、pnmtoddif、pnmtofits、pnmtops、pnmtorast、pnmtosgi、pnmtosir、pnmtotiff、pnmtoxwd、ppm3d、ppmbrighten、ppmchange、ppmdim、ppmdist、ppmdither、ppmflash、ppmforge、ppmhist、ppmmake、ppmmerge、ppmmix、ppmnorm、ppmntsc、ppmpat、ppmquant、ppmquantall、ppmqvga、ppmrelief、ppmshift、ppmspread、ppmtoacad、ppmtobmp、ppmtogif、ppmtoicr、ppmtoilbm、ppmtomap、ppmtomitsu、ppmtopcx、ppmtopgm、ppmtopi1、ppmtopict、ppmtopj、ppmtopjxl、ppmtopuzz、ppmtorgb3、ppmtosixel、ppmtotga、ppmtouil、ppmtoxpm、ppmtoyuv、ppmtoyuvsplit、psidtopgm、pstopnm、qrttoppm、rasttopnm、rawtopgm、rawtoppm、rgb3toppm、sgitopnm、sirtopnm、sldtoppm、spctoppm、spottopgm、sputoppm、tgatoppm、tifftopnm、xbmtopbm、ximtoppm、xpmtoppm、xvminitoppm、xwdtopnm、ybmtopbm、yuvsplittoppm、yuvtoppm、zeisstopnm
なお、
% cat foo.gif giftopnm | ppmtopgm | pgmtopbm | pbmtoascii
とすることで、GIF ファイルをテキスト形式に変換できる (アスキーアート)。縮小版は
% cat foo.gif giftopnm | ppmtopgm | pgmtopbm | pbmtoascii -2x4
とする。

netscape www ブラウザ

とっても有名なブラウザだったが、IE にシェアを奪われ、困った Netscape 社(AOL 社に買収された) はソースを公開し、オープンソースプロジェクトへ移行した。Netscape 社は mozilla.org の成果物をテスト・デバッグし、Java plugin などの付加機能を追加し、Netscape 6.x としてリリースしている。

netscape には -remote オプションというものがあり、netscape のプロセスが実行中ならば外部から netscape をある程度操作できる。
openURL(URL) 指定した URL を開く。
openURL(URL,new-window) 指定した URL を新しいウィンドウで開く。
openURL(FILE) 指定したファイルを開く。
openURL(FILE,new-window) 指定したファイルを新しいウィンドウで開く。
addBookmark(URL) 指定したURLをブックマークに追加する。
addBookmark(URL,Title) 指定したURLを、指定したタイトルでブックマークに追加する。
() や URL がシェルに解釈されないように、シングルクォートで囲むこと。
% netscape -remote 'openURL(http://hoge/fuga.html)'
% netscape -remote 'openURL(file:/home/username/.cshrc)'
さらに詳しい説明は http://home.netscape.com/newsref/std/x-remote.html を参照。

ちなみに Solaris 用の MSIE もあるが、日本語は表示できなかった。

netstat ネットワークの使用状況を表示

netstat の出力を理解するには、TCP/IP やソケットに関する理解が必須である。一通り解説はするが、ネットワークの初心者が理解できるとは到底思えない。少なくとも
を読んで、クライアントとサーバの意味、ポート番号などの考え方を知ってほしい。

ソケットの状態表示
UNIX で使われるプロトコルは、主にインターネットプロトコルファミリ (以下 PF_INET)、UNIX ドメインプロトコルファミリ (以下 PF_LOCAL。PF_UNIX とも言う) の2つがある。PF_INET とはいわゆるインターネットのことで、IP というプロトコルを利用する。一方、PF_LOCAL は、そのホスト内で閉じたネットワークのことで、X サーバや canna サーバ、syslogd などが使用する。

PF_INET は他のホストとも通信ができるという利点があるが、動作が遅い。PF_LOCAL は他のホストとは通信ができないが、動作は速い。

PF_INET にはポートという概念がある。PF_INET のサーバプロセスとは、特定のポートを見張っているものを指し、PF_INET のクライアントはそのポートに接続しているものを指す。一方 PF_LOCAL は、UNIX ドメインソケットという特殊なファイルを使って通信する。PF_LOCAL のサーバは UNIX ドメインソケットを作り、PF_LOCAL のクライアントは、その UNIX ドメインソケットに対して読み書きすることで通信が行われる。

さらに、PF_INET・PF_LOCAL にはそれぞれ TCP と UDP がある。TCP はコネクションを確立するので信頼性が高いが、速度が遅い。一方 UDP はコネクションを確立せず、信頼性は低い。例えばデータを送っても本当に届いたかどうかはわからないが、その分 速度は速い。

HTTP・SMTP・POP・FTP・telnet などは全て TCP/IP を利用している。一方、UDP/IP は DNS・NFS・syslog などが利用する。

以上の知識をふまえて、netstat の実行例を見てみよう。まずは -f inet を指定して、PF_INET のみを表示する。デフォルトでは、サーバが LISTEN しているソケットの情報は表示しないようになっているが、-a オプションを付加することで全ての state のソケット情報を取得できる。
% netstat -f inet -a
Active Internet connections (including servers)
Proto Recv-Q Send-Q  Local Address          Foreign Address        (state)
tcp4       0      0  192.168.1.12.http      192.168.1.11.4164      FIN_WAIT_2
tcp4       0      0  192.168.1.12.http      192.168.1.11.4163      FIN_WAIT_2
tcp4       0     20  192.168.1.12.ssh       192.168.1.11.3899      ESTABLISHED
tcp4       0      0  *.telnet               *.*                    LISTEN
tcp4       0      0  *.ftp                  *.*                    LISTEN
tcp4       0      0  *.canna                *.*                    LISTEN
tcp4       0      0  *.http                 *.*                    LISTEN
tcp4       0      0  *.submission           *.*                    LISTEN
tcp4       0      0  *.smtp                 *.*                    LISTEN
tcp4       0      0  *.ssh                  *.*                    LISTEN
udp4       0      0  *.6000                 *.*
udp4       0      0  X68000.ntp             *.*
udp4       0      0  192.168.1.12.ntp       *.*
udp4       0      0  *.ntp                  *.*
udp4       0      0  *.syslog               *.*
例えば
tcp4 0 0 *.telnet *.* LISTEN
は、telnet 用のポートを意味が LISTEN していることを意味する。この「telnet」という文字列は、実際に使用されているポート番号を /etc/services で検索し、対応するサービス名に置き換えたものである。例えば
% grep telnet /etc/services
telnet 23/tcp
となるので、ポート番号は 23 番であることがわかる。この「ポート番号→サービス名」の変換を抑止したい場合は -n オプションを使うとよい。

TCP で LISTEN しているのは 7 プロセス。telnet サーバ・ftp サーバ・canna サーバ・HTTP サーバ・ SMTP サーバ・SSH サーバであることがわかる。一方、UDP は ntp・syslog サーバが起動している。
UDP には状態が存在しないので、「state」の欄は何も表示されていない。

該当ポートを使用しているプロセスを特定するには、FreeBSD なら sockstat を、Linux なら fuser を、Solaris なら… (忘れた) を使う。標準コマンドではないが、lsof をインストールする手もある。

% netstat -f unix -a -n
Active UNIX domain sockets
Address  Type   Recv-Q Send-Q    Inode     Conn     Refs  Nextref Addr
c2ed28c0 stream      0      0        0 c2ed2a64        0        0
c2ed2a64 stream      0      0        0 c2ed28c0        0        0
c2ed2348 stream      0      0 c3422104        0        0        0 /tmp/ssh-BbnNCH0M/agent.2932
c2ed2460 stream      0      0 c316da28        0        0        0 /tmp/ssh-pGeomhlL/agent.600
c2ed2b7c stream      0      0 c2f60820        0        0        0 /tmp/.iroha_unix/IROHA
c2ed2c08 dgram       0      0        0 c2ed3000        0 c2ed2c94
c2ed2c94 dgram       0      0        0 c2ed3000        0 c2ed2d20
c2ed2d20 dgram       0      0        0 c2ed3000        0 c2ed2ec4
c2ed2ec4 dgram       0      0        0 c2ed3000        0        0
c2ed3000 dgram       0      0 c2ecd30c        0 c2ed2c08        0 /var/run/log

インタフェース情報表示
% netstat  -i
Name    Mtu Network       Address              Ipkts Ierrs    Opkts Oerrs  Coll
fxp0   1500 <Link#1>      00:a0:c9:ab:fb:8a    72980     0    67575     0     0
fxp0   1500 192.168.1     192.168.1.12         71968     -    67518     -     -
fxp0   1500 fe80:1::2a0:c fe80:1::2a0:c9ff:        0     -        4     -     -
plip0  1500 <Link#2>                               0     0        0     0     0
lo0   16384 <Link#3>                              76     0       76     0     0
lo0   16384 your-net      X68000                  48     -       48     -     -
lo0   16384 localhost     ::1                      0     -        0     -     -
lo0   16384 fe80:3::1     fe80:3::1                0     -        0     -     -

netstat コマンドのオプション
-a サーバプロセスが利用している PF_INET ソケットも表示する。
デフォルトでは、サーバが listen している PF_INET ソケットの情報は表示しないようになっているが、これを表示するようのが -a オプションである。
-f 指定したプロトコルの情報のみを表示
% netstat -f inet (インターネットプロトコルのみ表示)
% netstat -f unix (UNIX ドメインプロトコルのみ表示)
-i 指定したネットワークインタフェースの情報のみ表示。tun0 や ppp、ed1 など。
-p 指定したプロトコルのみを表示。
ここでのプロトコルというのは、インターネットプロトコルや UNIX ドメインプロトコルではなく、HTTP・FTP・telnet などのことである。/etc/services に書いてあるプロトコルから選択するとよい。
-n ホスト名・サービス名を表示しない。
デフォルトでは、IP アドレスはホスト名に (DNS サーバに問い合わせる)、ポート番号はサービス名に (/etc/services を使う) 変換されて表示される。しかし、逆引き (IP アドレスからホスト名への変換) に時間がかかるホストがあると、そこで netstat の表示がしばらく止まってしまう。-n オプションを付けると、IP アドレスの逆引きを行わなくなるので、このような IP アドレスがあってもすぐに表示される。
-s ネットワークの統計情報を表示する
>> OSオンラインマニュアル(man) Linux netstat(8)
>> OSオンラインマニュアル(man) FreeBSD netstat(1)

newaliases /etc/aliases の情報を更新する。

/etc/aliases を書き換えたら、必ず newaliases を実行しないといけない。これを行わないと、いつまでたっても変更内容が反映されない。

まぎらわしいことに、newalias というコマンドがインストールされている環境もある。これは sendmail とは全く関係ないコマンドなので注意。LASER5 Linux を使ったとき これではまった。
>> OSオンラインマニュアル(man) FreeBSD newaliases(1)
>> OSオンラインマニュアル(man) Linux newaliases(1)

nice プライオリティ (優先順位) を変更して実行する

UNIX では同時に複数のプロセスを実行できるが、その際どのプロセスを優先的に実行するかを指定できる。プライオリティとはプロセスの優先度のことで、値が低いほどスケジューリングにおける優先度が高くなる。

プライオリティは -20 から 20 までの値を取る。つまり -20 が最も優先順位が高く、高速に動くわけである。逆に、重要でないプロセスの優先度を低く設定しておけば、他のプロセスが実行される機会が増えることになる。

csh・tcsh 内部コマンドの nice と、/usr/bin/nice があり、それぞれ書式が違うので注意。内部コマンドの nice は、プライオリティの前に必ず +- を付けなければならない。
% nice +20 xeyes
⇒ xeyes をプライオリティ 20 (優先度が低い) で実行
# nice -20 xeyes
⇒ xeyes をプライオリティ -20 (優先度が高い) で実行。マイナスの値は root しか指定できない。

一方、/usr/bin/nice の場合は、20、-20 を指定する場合は、
% /usr/bin/nice -20 xeyes
# /usr/bin/nice --20 xeyes
となる。sh・bash には内部コマンドの nice はないので、sh・bash で nice を使う場合はこの書式になる。

既に実行してあるプロセスのプライオリティを変更するには、renice コマンドを使う。
>> OSオンラインマニュアル(man) Solaris10 nice(1)
>> OSオンラインマニュアル(man) FreeBSD nice(1)
>> OSオンラインマニュアル(man) Linux nice(1)
>> OSオンラインマニュアル(man) Linux nice(2)

nkf 文字コードを変換する (パイプ)。また、MIME、ROT13/47 なども変換できる。

文字コードには主に JIS (ISO-2022-JP)、SJIS (Shift_JIS)、EUC-JP の3種類がある。普通の UNIX では EUC-JP (ただしメール・ネットニュースでは JIS)、Windows や Mac では Shift_JIS がよく使われる。

-j JIS (ISO-2022-JP) コードに変換
-s SJIS (Shift_JIS) コードに変換
-e EUC-JP (EUC-JP) コードに変換
% nkf -e sample > sample.euc
⇒ ファイル sample の文字コードを EUC に変換して sample.euc に出力する
-f 日本語を含む文章の fold。
% nkf -f 30 < file
⇒ file の出力を1行あたり30文字に整形する。
fold コマンドと違い、日本語を含む文章でも正しく処理することができる。
-m MIME をデコード
メールの Subjectなどには生の日本語ではなく、MIME を書く。例えば
=?iso-2022-jp?B?GyRCJE8kOCRhJF4kNyRGGyhK?=
を MIME デコードすると
% echo '=?iso-2022-jp?B?GyRCJE8kOCRhJF4kNyRGGyhK?='|nkf -m
はじめまして
となる。nkf のバージョンが古い場合、iso-2022-jp の部分が小文字だと変換できないことがある。この場合は「iso-2022-jp」を「ISO-2022-JP」に変えればよい。
-MB Base64 形式にエンコードする
% echo -n 'abcdefg' | nkf -MB
YWJjZGVmZw==
-x 半角カナを維持する
nkf はデフォルトではいわゆる半角カナを全角カナに置換してしまう。置換を抑止するためには -x オプションを指定する。

nkf にはファイルを直接書き換える機能はない。複数のファイルの文字コードを一括して変換したい場合は qkc を使うこと。

ファイル内容ではなくファイル名の文字コードを変更する場合は、convmv コマンドを使うとよい。

nm 実行ファイル、ライブラリのシンボルテーブルを表示

目的のライブラリ関数が、どのライブラリに入っているかは nm コマンドで探すとよい。例えば sin 関数がどのライブラリに入っているかわからないときは
% nm -o /usr/lib/*.a /usr/X11R6/lib/*.a | grep sin
とすればよい。参照のみのシンボル (実体がない) は
U _sin
と表示されるので、
% nm -o /usr/lib/*.a /usr/X11R6/lib/*.a | grep sin | grep -v ' U '
とすると、参照のみのシンボルを除外できる。

nm -D /usr/lib/libc.so
>> OSオンラインマニュアル(man) FreeBSD nm(1)
>> OSオンラインマニュアル(man) Solaris10 nm(1)
>> OSオンラインマニュアル(man) Linux nm(1)

nohup ログアウトしても処理を中断させない

プログラムをバックグラウンドで実行し、その後ログアウトすると、そのとき実行していたプロセスには自動的に SIGHUP シグナルが送られ、プロセスは終了する。しかし、
% nohup command &
としてコマンドを実行すると、ログアウトしても command には SIGHUP シグナルが送られない。つまりログアウト後も実行を続けさせることができる。実行に長い時間がかかるプロセスに使うと、ログアウト後にも処理を続けさせることができて便利である。

csh・tcsh には内部コマンドの nohup があるが、sh・bash にはない。sh・bash が実行するのは /usr/bin/nohup であることに注意。
>> OSオンラインマニュアル(man) Solaris10 nohup(1)
>> OSオンラインマニュアル(man) FreeBSD nohup(1)
>> OSオンラインマニュアル(man) Linux nohup(1)

nslookup IP アドレスを FQDN に、FQDN を IP アドレスに変換する

DNS サーバに問い合わせて、IP アドレスを FQDN に、あるいはその逆に、FQDN を IP アドレスに変換する。

FreeBSD での名前解決は、
  • /etc/host.conf を参照。/etc/hosts を先に参照するか、DNS に問い合わせるかを調べる。
hosts、bind の順で書いてあったら、先に /etc/hosts を参照し、その後 DNS サーバに問い合わせ。
bind、hosts の順で書いてあったら、先に DNS サーバに問い合わせ、その後に /etc/hosts を参照。
  • /etc/hosts を参照。ここで見付かれば終了。
  • /etc/resolv.conf を参照し、DNS サーバの IP アドレスを取得
  • DNS サーバと通信し、名前解決
のような手順となる。

ここらへんの設定ファイルは OS によってかなり異なり、Solaris だと /etc/host.conf はなく、/etc/nsswitch.conf だったりする。
>> OSオンラインマニュアル(man) Linux nslookup(8)
>> OSオンラインマニュアル(man) FreeBSD nslookup(1)

ntpd NTP サーバ (デーモン)

時刻あわせを行う。設定ファイルは /etc/ntp.conf。

ntpdate 自動的に時刻を修正する

NTP (Network Time Protocol) という、マシンの時刻を自動的に同期させるシステムがある。ntpdate は NTP クライアントで、NTP サーバにアクセスして時刻を取得し、ローカルホストの時刻を修正する。NTP サーバとしては ntp.nict.jp や ntp.jst.mfeed.ad.jp などがあり、
# ntpdate ntp.nict.jp
などとすることで正確な時刻に修正することができる。マシンの時刻を変更するわけなので、root しか実行できない。常に正確な時刻に合わせたいなら、/etc/daily に
/usr/sbin/ntpdate ntp.nict.jp
という行を追加しておけばよい。

なお、当然のことながら基準となる NTP サーバの時刻が狂っているとどうにもならない。
>> OSオンラインマニュアル(man) FreeBSD ntpdate(8)

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

od コマンドはファイルや標準入力のデータを 8進数・10進数・16進数で表示する。od は "Octal Dump" の略なので、デフォルトは 8進数ダンプとなる。
% od file.txt
0000000 020474 026455 044444 035144 064440 062156 074145 064056
0000020 066564 026154 020166 027061 032063 031040 030060 027471
0000040 032060 030457 020070

これではさすがにわかりづらいので、-tcx1 オプションの使用をお勧めする。
% echo abcdefghijklmnopqrstu | od -tx1c
0000000    61  62  63  64  65  66  67  68  69  6a  6b  6c  6d  6e  6f  70
           a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p
0000020    71  72  73  74  75  0a
           q   r   s   t   u  \n
0000026

-t オプション
od コマンドの -t オプションは無駄に汎用的で、わかりづらいオプションである。-t の後には以下のようなフォーマットを表す文字を指定する。
x[長さ] 16進数表記
d[長さ] 10進数表記
o[長さ] 8進数表記
c 文字表記 (改行コードなどは \r や \n のように表記)
a 文字表記 (改行コードなどは CR や LF のように表記)
x・d・o の場合、最後に長さを指定することで、何バイト単位でダンプするかを指定できる。省略時は 2となるが、2バイト単位でダンプしたい場合などまずない。忘れずに "1" を付加しよう。つまり以下のようになる。
  • -tx1 … 1バイト単位で 16進数表記
  • -tx2 … 2バイト単位で 16進数表記
  • -tx4 … 4バイト単位で 16進数表記
  • -td1 … 1バイト単位で 10進数表記
  • -td2 … 2バイト単位で 10進数表記
  • -td4 … 4バイト単位で 10進数表記
  • -tx … (省略したので) 2バイト単位で 16進数表記
  • -td … (省略したので) 2バイト単位で 10進数表記

さらに -t オプションは複数指定することができるので、ある入力に対して「文字表記したもの」と「16進数表記したもの」の 2パターンを表示する、ということも可能である。例えば、上記の例の
% echo abcdefghijklmnopqrstu | od -tx1c
0000000    61  62  63  64  65  66  67  68  69  6a  6b  6c  6d  6e  6f  70
           a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p
は、「-tx1」(1バイト単位で16進数) と「-tc」(文字表記) を組み合わせたものである。

以下に理解を深めるためのさらなる例を示す。
% echo abcdefghijklmnopqrstu | od -tcx1
0000000    a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p
           61  62  63  64  65  66  67  68  69  6a  6b  6c  6d  6e  6f  70
⇒ x1 と c の順序を逆にしたので、"a" と "61" の行が逆になった
% echo abcdefghijklmnopqrstu | od -tx1ccc 0000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 a b c d e f g h i j k l m n o p a b c d e f g h i j k l m n o p a b c d e f g h i j k l m n o p
⇒ 同じフォーマット (c) を複数回指定したので、同じ出力が何度も行われる
% echo abcdefghijklmnopqrstu | od -tx1d1o1c 0000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 141 142 143 144 145 146 147 150 151 152 153 154 155 156 157 160 a b c d e f g h i j k l m n o p
⇒ 16進数・10進数・8進数・文字表記の順

個人的には hd コマンドの出力の方がわかりやすいと思う。ただし hexdump や hd は必ずインストールされているとは限らないが、od コマンドはほとんどの UNIX にデフォルトで含まれているのが強み。
>> OSオンラインマニュアル(man) Linux od(1)
>> OSオンラインマニュアル(man) Solaris10 od(1)
>> OSオンラインマニュアル(man) FreeBSD od(1)

oneko ねこがマウスを追いかける

-tora トラじまのねこ

openssl 暗号化・復号化・公開鍵などを扱うツール

openssl 単体で多くの機能を提供しているため非常にわかりにくいが (なんでもかんでも詰め込みすぎだ)、基本は
% openssl コマンド [コマンドごとの引数…]
である。


openssl が受け付けるコマンド一覧
openssl が受け付けるコマンドの一覧は以下の通り。
asn1parse ASN.1 データを解析・表示する
ca CA を扱う
ciphers SSL/TLS で使用できる暗号スイート一覧を表示する
crl 証明書取消リスト (CRL) を扱う
crl2pkcs7 証明書取消リスト (CRL) を PKCS#7 形式に変換する
dgst メッセージダイジェストを計算
dsa DSA データを扱う
dsaparam DSA パラメータを生成する
enc 暗号化処理を行う
errstr エラー番号をエラー文字列に変換
dhparam Diffie-Hellman パラメータを生成する
gendsa DSA 秘密鍵を生成
genrsa RSA 秘密鍵を生成
passwd UNIX パスワードを生成
pkcs12 PKCS#12 (電子証明書や秘密鍵の形式) のデータを扱う
pkcs7 PKCS#7 (暗号化や署名を行ったデータの形式) のデータを扱う
req PKCS#10 (証明書発行要求の形式) のデータを扱う
rsa RSA 鍵を表示・操作する
rand 乱数を生成
rsautl RSA による暗号化・復号化・署名・検証を行う
s_client SSL/TLS で指定サーバに接続
s_server SSL/TLS でデータを受け付けるサーバとして動作
s_time SSL/TLS コネクションタイマ
sess_id SSL/TLS セッションデータ管理
smime S/MIME メール処理
spkac Netscape の SPKAC (Signed Public Key And Challenge) ファイルを操作
speed アルゴリズム速度を計測
verify X.509 公開鍵証明書を検証する
version OpenSSL のバージョンを表示
x509 X.509 公開鍵証明書を操作する

-help オプション
openssl -help で、使用可能なコマンドの一覧等を表示できる。
% openssl -help

また、openssl [コマンド] -help で、それぞれのコマンドに対する引数やオプションの解説を表示することができる。コマンドごとに引数やオプションが大きく異なるので、有用である (下記は openssl dgst のヘルプ)。
% openssl dgst -help
unknown option '-help'
options are
-c to output the digest with separating colons
-r to output the digest in coreutils format
-d to output debug info
-hex output as hex dump
(略)
なお、実際は "unknown option '-help'" とあるように、不正オプションとみなされているだけであるが、コマンドごとのヘルプを表示するオプションは存在しないので、世の中の人は "-help" や "--help" などを渡してヘルプを表示しているようである。

OpenSSL で使用可能な共通鍵暗号の一覧
OpenSSL で使用可能な暗号は以下のようにして調べることができる。
% openssl enc --help
...
Cipher Types
-aes-128-cbc               -aes-128-cfb               -aes-128-ecb              
-aes-128-ofb               -aes-192-cbc               -aes-192-cfb              
-aes-192-ecb               -aes-192-ofb               -aes-256-cbc              
-aes-256-cfb               -aes-256-ecb               -aes-256-ofb              
-aes128                    -aes192                    -aes256                   
-bf                        -bf-cbc                    -bf-cfb                   
-bf-ecb                    -bf-ofb                    -blowfish                 
-cast                      -cast-cbc                  -cast5-cbc                
-cast5-cfb                 -cast5-ecb                 -cast5-ofb                
-des                       -des-cbc                   -des-cfb                  
-des-ecb                   -des-ede                   -des-ede-cbc              
-des-ede-cfb               -des-ede-ofb               -des-ede3                 
-des-ede3-cbc              -des-ede3-cfb              -des-ede3-ofb             
-des-ofb                   -des3                      -desx                     
-desx-cbc                  -rc2                       -rc2-40-cbc               
-rc2-64-cbc                -rc2-cbc                   -rc2-cfb                  
-rc2-ecb                   -rc2-ofb                   -rc4                      
-rc4-40                    -rc5                       -rc5-cbc
-rc5-cfb                   -rc5-ecb                   -rc5-ofb
これらは全て共通鍵暗号方式であることに注意すること。

上記の例では、共通鍵暗号方式アルゴリズムとして AES、Blowfish (BF)、CAST、DES、DESX、IDEA、RC2、RC4、RC5 が利用可能であることがわかる。

また、EDE とあるのは Encrypt-Decrypt-Encrypt (暗号化-復号化-暗号化) のことで、2 つまたは 3 つの鍵を使って
暗号化 → 復号化 → 暗号化
を繰り返すことである。鍵を 2つ使う方式は
鍵 A で暗号化 → 鍵 B で復号化 → 鍵 A で暗号化
で、上記の暗号リストでは単に EDE と記述してある。鍵を 3つ使う方式は
鍵 A で暗号化 → 鍵 B で復号化 → 鍵 C で暗号化
となり、上記の暗号リストでは EDE3 となっている。

また、cbc・ede・ofb・ecb などは暗号モードである。下記にて説明する。

CBC・CFB・ECB・OFB などの暗号モードの説明
上記の CBC・CFB・ECB・OFB とは、暗号モードと呼ばれるものである。

CBC・CFB・ECB・OFB はブロック暗号のモードのこと。例えば一度に 4bit のデータを暗号化できる暗号方式があるとしよう (鍵のことではない。暗号化の対象となるデータ長のこと)。ここで 16bit のデータを暗号化するためには、データを 4bit ごとに区切って 4回暗号化を繰り返さないといけない。ある鍵によって 1111 が 1010 に暗号化される場合、もし入力データが全て 1 だったとしたら、
1111 1111 1111 1111 → 1010 1010 1010 1010
となってしまう。これは解読者に「各 4bit が同じデータである」という解読のためのヒントを与えてしまうので、非常にまずい。また、暗号化されたデータの一部を置き換えることで (解読しなくても) 解読後のデータを差し替えることができてしまう。つまり、各ブロックが完全に独立しているのが問題なのである。

上記のような欠点を防ぐために、ブロックの内容が同じであっても、出力結果が同じにならないための工夫がある。その工夫にはいくつかの種類があり、それが CBC・CFB・ECB・OFB である。詳しい説明は省略するが、以下、3 つはおすすめしないモード。
ECB (Electric CodeBook) … 電子符号表モード
CFB (Cipher FeedBack) … 暗号フィードバックモード
OFB (Output FeedBack) … 出力フィードバックモード
そしておすすめなのは、これ。
CBC (Cipher Block Chaining) … 暗号ブロック連鎖モード

ちなみに上記の例では 4bit ブロック暗号方式を例にあげたが、DES は 64bit ブロック暗号、AES は 128・192・256 bit からブロックを選択可能である。

openssl ciphers … SSL/TLS で使用できる暗号スイート一覧を表示する
% openssl ciphers
AES256-SHA:DHE-RSA-AES256-SHA:(略):EXP-RC4-MD5:EXP-RC4-MD5
⇒ この環境の OpenSSL で使用できる SSL/TLS の暗号スイート一覧を表示する。

% openssl ciphers -v
AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
(略)
EXP-RC4-MD5 SSLv3 Kx=RSA(512) Au=RSA Enc=RC4(40) Mac=MD5 export
EXP-RC4-MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=RC4(40) Mac=MD5 export
-v オプションを付けることで、それぞれの暗号スイートの意味を少しだけわかりやすく表示してくれる。例えば一行目の「AES256-SHA」は
  • SSLv3 で使用可能
  • 公開鍵暗号方式は RSA
  • 共通鍵暗号方法は AES 256bit
  • ハッシュ関数 SHA1
であることがわかる。

% openssl ciphers [暗号スイートリスト...]
暗号スイートを指定して、使用可能な暗号スイートを表示する。用途としては、Apache の httpd.conf における SSLCipherSuite ディレクティブの内容を確認するとか、SSL/TLS クライアントを作る際の SSL_CTX_set_cipher_list 関数に渡す文字列を確認するなど、マイナーなところで大活躍している。

暗号スイートリストは openssl ciphers で表示される「DHE-RSA-AES256-SHA」のような暗号スイート名に加え、さらに以下のキーワードを使用できる。
DEFAULT デフォルトの暗号スイート。ALL:!ADH:RC4+RSA:+SSLv2:@STRENGTH と同じ
ALL 使用可能な全ての暗号スイート。ただし eNULL を除く。
COMPLEMENTOFDEFAULT ALL に含まれるが DEFALUT には含まれない暗号スイート
COMPLEMENTOFALL 使用可能であるが ALL に含まれない暗号スイート。つまり eNULL
HIGH 共通鍵暗号方式の鍵長が 128bit より大きい暗号スイート
MEDIUM 共通鍵暗号方式の鍵長が 128bit の暗号スイート
LOW 共通鍵暗号方式の鍵長が 56bit または 64bit の暗号スイート
EXP, EXPORT 米国外に輸出可能な暗号スイート
EXPORT40 米国外に輸出可能で共通鍵暗号方式の鍵長が 40bit の暗号スイート
EXPORT56 米国外に輸出可能で共通鍵暗号方式の鍵長が 56bit の暗号スイート
AES 共通鍵暗号方式に AES を使った暗号スイート
3DES 共通鍵暗号方式に 3DES を使った暗号スイート
DES 共通鍵暗号方式に DES を使った暗号スイート
RC4 共通鍵暗号方式に RC4 を使った暗号スイート
RC2 共通鍵暗号方式に RC2 を使った暗号スイート
IDEA 共通鍵暗号方式に IDEA を使った暗号スイート
MD5 ハッシュアルゴリズムに MD5 を使った暗号スイート
SHA1, SHA ハッシュアルゴリズムに SHA1 を使った暗号スイート
ADH 認証に 匿名 DH (Anonymous Diffie-Hellman) を使った暗号スイート
DH 認証に DH (Diffie-Hellman) を使った暗号スイート。ADH を含む
暗号スイートやキーワードはコロンでつなぐことで複数指定することができる。
% openssl ciphers AES256-SHA:MD5
AES256-SHA:(略):EXP-RC4-MD5
⇒ AES256-SHA と、ハッシュアルゴリズムに MD5 を使った暗号スイート

もしタイプミスをしていたり、コンパイルオプションなどで特定の暗号が使用できない状況になっていた場合は、以下のように暗号スイートが表示されない。
% openssl ciphers AES256-SHA:MD5
⇒ 何も表示されない。この環境では適合する暗号スイートがないということ

暗号スイートやキーワードは「A+B」とすることで AND 条件を取ることができる。
% openssl ciphers AES+SHA
⇒ 共通鍵暗号方式に AES を使い、なおかつハッシュアルゴリズムに SHA1 を使う暗号スイート
% openssl ciphers AES:SHA
⇒ コロンで結ぶと「共通鍵暗号方式に AES を使う暗号スイートと、ハッシュアルゴリズムに SHA1 を使う暗号スイートを並べたもの」となってしまうことに注意

文字列の先頭に `-' を付けることで、その暗号スイートを削除することができる。
% openssl ciphers ALL:-RC4
⇒ 全ての暗号スイートから RC4 が関係するものを除いたもの
% openssl ciphers ALL:-RC4:MD5
⇒ 全ての暗号スイートから RC4 が関係するものを除き、さらに MD5 に関係するものを加える。一度 `-' で取り除いたものを後から加えることも可能なため、最終的に暗号スイート「RC4-MD5」は表示される。

一度取り除いた暗号スイートを二度と追加させないようにするには、`!' を使う。
% openssl ciphers ALL:\!RC4:MD5
⇒ 全ての暗号スイートから RC4 が関係するものを除き、さらに MD5 に関係するものを加える (このとき RC4 に関係する暗号スイートは追加されない)。最終的に暗号スイート「RC4-MD5」は表示されない。

`+' を使うと、暗号スイートを右側に移動させることができる。つまり削除はしないまでも優先度を下げる効果がある。これは暗号スイートの追加ではなく、ただの移動であることに注意。暗号スイートの追加は「FOO:BAR」などとコロンで結ぶだけでよい。
% openssl ciphers ALL:+LOW
⇒ 全ての暗号スイートから LOW にマッチするものを右側に移動
`+' には「+LOW」 などの優先度を下げる使い方と、「AES+SHA」などのキーワードの AND 条件を取る使い方があることに注意しよう。

@STRENGTH を使うことで暗号強度の強い順にソートできる。
% openssl ciphers AES:SHA1:@STRENGTH
⇒ AES が関係する暗号スイートと SHA1 が関係する暗号スイートを、暗号強度順にソート
% openssl ciphers AES:SHA1:@STRENGTH:+RSA
⇒ AES が関係する暗号スイートと SHA1 が関係する暗号スイートを、暗号強度順にソートし、その後に RSA が関係する暗号スイートの優先度を下げる

openssl dgst … メッセージダイジェストを計算する
% echo -n hoge | openssl dgst -md5
ea703e7aa1efda0064eaa507d9e8ab7e
⇒ 文字列 hoge の MD5 値を表示
% openssl dgst -sha1 file.txt
31f30ddbcb1bf8446576f0e64aa4c88a9f055e3c
⇒ ファイル file.txt の SHA1 値を表示
使用できるメッセージダイジェスト関数は、OpenSSL 0.9.7a では以下の通り。
-md2 -md4 -md5 -sha -sha1 -mdc2 -ripemd160

openssl enc … 共通鍵暗号方式で暗号化・復号化
plain.txt を AES 128bit で暗号化し、crypted に出力する。
% openssl enc -e -aes128 -in plain.txt -out crypted
enter aes-128-cbc encryption password: (パスワードを入力)
Verifying - enter aes-128-cbc encryption password: (再度パスワードを入力)
crypted を plain.txt に復号化する。
% openssl enc -d -aes128 -in crypted -out plain.txt
enter aes-128-cbc decryption password: (パスワードを入力)
Base64 エンコード・デコードも可能。
% echo -n abcdefg | openssl enc -e -base64
YWJjZGVmZw==
⇒ abcdefg を Base64 にエンコード
% echo YWJjZGVmZw== | openssl enc -d -base64
abcdefg
⇒ YWJjZGVmZw== を Base64 デコードして abcdefg に戻す


% openssl genrsa -out private-key.pem 2048
2048bit の秘密鍵を生成し、ファイル private-key.pem に出力する。RSA における秘密鍵は OpenSSL によって自動生成されることに注意しよう。ユーザがパスワードやパスフレーズの入力をするのではない。ファイルの内容は以下のようなものになる。
-----BEGIN RSA PRIVATE KEY-----
MIIBPAIBAAJBALZGuIEVleemeQK1Tbl/NamcR3lVEAjikK8op0wQ6yqAtXdo7DiC
Ym06guFtMPbqcBRRvSoCdz5xpYgwj8IeqVUCAwEAAQJAPzIx0f9r487h8cBuXDvw
nQej+Ds3vfzfcPtFVaggALHdZ6Y2Vvh5OgalFkvuawI1r7Watq4a5/QyZehDYWhV
QQIhANwoIen1QeoTGYVlwOI7sXhEHlf1EFRgFuQaqjNzyG6dAiEA0/PGNYMxJTLm
ZCgKcX1REhxH6xiW/nRHNx4iAW7mjBkCIQCmKqBWTqf+fYYAumlYGAf+JyPj7XLy
zEfayQl3pkc8vQIhAMAzoZxJObnH7JEKll3QDEJmDvmsNNDOVP4wfxnZnYuRAiEA
qHBG2F18IA1oJbpcnw31nm5xfwHtRUv/zvX4KRbCdfg=
-----END RSA PRIVATE KEY-----
このファイルは絶対に公開してはいけない。作成直後に
% chmod 400 private-key.pem
とパーミッションを落としておくことを推奨する。

% openssl genrsa -out private-key-crypted-aes256.pem -aes256 2048
Enter pass phrase for private-key-crypted-aes256.pem:
→ パスフレーズ入力を求められているので、自分で決めたパスフレーズを入力する
Verifying - Enter pass phrase for private-key-crypted-aes256.pem:
→ 上記で入力したパスフレーズをもう一度入力
2048bit 秘密鍵を生成した上で、AES 256bit で暗号化する (その際のパスフレーズを入力する)。上で述べたとおり、RSA における秘密鍵は openssl コマンドが勝手に決めるものである。ここで入力するパスフレーズは、AES の鍵であり、RSA の秘密鍵とは何の関係もない。

RSA において秘密鍵がばれるというのは全ての暗号が解読可能になるという重大な事態につながる。よって、秘密鍵をファイルにそのまま保存しておくのはあまりよろしくない。そこで RSA の秘密鍵を共通鍵暗号の AES で暗号化しておくのである。

出力は以下のようなものになる。
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,C0714916A3315F5F1F1A6BE431F1BF07

NtWrAcXY8KU9ze/RfZf/tkouDhEh4dB4ECG0BABSSTVlckcYaH2Y3cuHnDXCoPvk
FyRa79eMV8oGdavmQl51L0GIPLMcv/O0OSRihQPYz01WFaMOncOqoZoTwwVZsWWT
v8kJq/dVlBmjEdXACpIpyKIRxTmU3agp9gdRQ+oGstI8kUgk3E6zqE+pJ6C96Y/Y
5lRKZnNigV1wv5GpvCLnVWTBqIh9Jc8odB4j3gaFKkuYkHx7laqqsyS2ObNbxxKi
nkunGJwit+KH3eRUgzh10Yw+FWzVs26ONj3uAcEWLqs5BfaRyJK/0/Ben1AZOeYA
o2TnvefrFZjlvln5jc8Drct51QeVAmrJKMQprgMZPwtacPRUtOAfJq0JDwne8scu
ys8VFiXA/G9f1UCbxjfyNSTStv+Z/dtMaqpra93zDDo=
-----END RSA PRIVATE KEY-----

RSA の秘密鍵をファイルにそのまま保存するか、暗号化して保存するかは、純粋に運用の問題である。例えば、apache などの web サーバに SSL/TLS を組み込む場合、RSA の秘密鍵を AES などで暗号化して保存しておくと、サーバを起動するたびに人間がパスフレーズを入力する必要がある。このような場合は、安全性が低くなることを承知の上で、RSA の秘密鍵を AES などで暗号化せずにそのまま保存しておく、という選択肢もある。

AES 128 以外にも以下の共通鍵暗号方式が使用できる。
-des … DES (鍵長 56ビット) で暗号化
-des3 … 3DES (Triple-DES。鍵長 112ビット) で暗号化
-aes128 … AES 鍵長 128ビットで暗号化
-aes192 … AES 鍵長 192ビットで暗号化
-aes256 … AES 鍵長 256ビットで暗号化
おすすめするのは当然ながら -aes256 である。

上記の例では引数に 2048 を指定したため、RSA 鍵長は 2048bit となる。古来より openssl genrsa のデフォルトは 1024bit であったのだが、(多分) NIST (米国標準技術研究所: National Institute of Standards and Technology) が米国の政府調達における指針として RSA 1024bit は不可としたため、2009〜2010年頃より SSL/TLS 認証局は 1024bit の鍵の受付を停止したため、2017年現在では 2048bit を使用する場合が多いだろう。ちなみに 4096bit や 8192bit も使えなくはないが、SSL/TLS 認証局により、2048bit のみ受付しているところや、8192bit まで対応しているところなどいろいろである。

ちなみにビット数が増えれば増えるほど、genrsa の時間もかかる。あるサーバでの実行時間を以下に示す。
  • openssl genrsa 1024: 0.085秒
  • openssl genrsa 2048: 0.173秒
  • openssl genrsa 4096: 0.722秒
  • openssl genrsa 8192: 31.59秒
  • openssl genrsa 16384: 8分29秒

なお、RSA の鍵長は 2のべき乗といった制限はないため、例えば 1234bit の鍵生成も可能である。

生成時に共通鍵暗号方式で暗号化しなかった鍵を暗号化したり、一度暗号化した鍵を復号化するには openssl rsa を使用する。

openssl rsa … RSA 鍵を表示・操作する
RSA 秘密鍵の内容を表示:
% openssl rsa -in private-key.pem -text
Private-Key: (512 bit)
modulus:
00:cf:d7:b2:2b:f2:3b:ce:92:58:0e:63:0e:40:a9:(略)
publicExponent: 65537 (0x10001)
privateExponent:
00:85:23:39:79:d7:30:a2:71:b2:40:7d:09:7b:38:(略)
prime1:
00:f2:02:fe:b2:24:ee:f6:01:8e:64:24:2f:dd:29:(略)
prime2:
00:db:db:1b:36:51:2e:e3:88:39:93:bd:dd:85:4d:(略)
exponent1:
00:86:e6:5a:78:8c:93:d2:f7:0d:1b:0e:fc:cb:27:(略)
exponent2:
00:91:58:52:af:20:10:7d:7f:8b:80:ee:9e:4a:08:(略)
coefficient:
00:d9:42:f6:06:fb:3a:10:80:08:e6:db:0e:6c:18:(略)
writing RSA key
(略)
秘密鍵には RSA 鍵の全ての情報が含まれていることに注意しよう。よって秘密鍵を公開してしまうと全てがおしまいなわけである。それぞれの数の意味は以下の通り。
  • modules: RSA 構造体の n に相当 (p*q)
  • publicExponent: RSA 構造体の e に相当
  • privateExponent: RSA 構造体の d に相当
  • prime1: RSA 構造体の p に相当 (素数)
  • prime2: RSA 構造体の q に相当 (素数)
  • exponent1: RSA 構造体の dmp1 に相当 (d mod (p-1))
  • exponent2: RSA 構造体の dmq1 に相当 (d mod (q-1))
  • cofficient: RSA 構造体の iqmp に相当 ((q-1) mod p)
解説は
を参照。

RSA 秘密鍵から、RSA 公開鍵を生成:
% openssl rsa -in private-key.pem -pubout -out public-key.pem
出力される公開鍵の内容は以下のようになる。
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALMM4iQMJAFwCkTD927ioG9jhJ0S6Wzj
Vc6QEgJIBbTLSs204VPyr78k8CFZNWQSM8ji0jgJXF8v/1OdkH/TaUUCAwEAAQ==
-----END PUBLIC KEY-----

RSA 公開鍵の内容を表示:
% openssl rsa -in publib-key.pem -pubin -text
Modulus (512 bit):
00:cf:d7:b2:2b:f2:3b:ce:92:58:0e:63:0e:40:a9:(略)
Exponent: 65537 (0x10001)
writing RSA key
(略)
⇒ このように公開鍵には e と n しか含まれていない。よって、公開しても問題はない。

RSA 秘密鍵を共通鍵暗号で暗号化:
% openssl rsa -in private.key -aes256 -out private-key-crypted-aes256.pem
共通鍵暗号で暗号化された RSA 秘密鍵を復号化:
% openssl rsa -in private-key-crypted-aes256.pem -out private.key

openssl rsautl … RSA による暗号化・復号化・署名・検証を行う
公開鍵による暗号化:
% openssl rsautl -pubin -inkey public-key.pem -in plain.txt -encrypt -out encrypted.dat
秘密鍵による復号化:
% openssl rsautl -inkey private-key.pem -in encrypted.dat -decrypt -out plain2.txt

openssl x509 … X.509 公開鍵証明書を操作する
証明書の内容を表示:
% openssl x509 -inform pem -in cert.pem -text
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 0 (0x0)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=AU, ST=Queensland, O=CryptSoft Pty Ltd, CN=Server test cert (512 bit)
Validity
Not Before: Sep 9 03:41:26 1997 GMT
Not After : Oct 9 03:41:26 1997 GMT
Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=Eric the Young
Subject Public Key Info:
Public Key Algorithm: dsaEncryption-old
DSA Public Key:
pub:
00:b5:44:a8:f3:83:9e:92:38:ad:28:65:63:c4:bb:(略)
Signature Algorithm: md5WithRSAEncryption
94:e5:24:a0:6a:92:52:75:15:c9:a1:7f:82:a4:2b:c5:cb:e2:(略)
PEM 形式を DER 形式に変換:
% openssl x509 -inform pem -outform der -in cert.pem -out cert.der
DER 形式を PEM 形式に変換:
% openssl x509 -inform der -outform pem -in cert.der -out cert.pem

openssl s_client … SSL/TLS で指定サーバに接続する
https://www.verisign.co.jp/ に接続し、
GET / HTTP/1.0
Host: www.verisign.co.jp
を送信する例。
% openssl s_client -connect www.verisign.co.jp:443
depth=2 /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
verify error:num=19:self signed certificate in certificate chain
verify return:0
(略)
New, TLSv1/SSLv3, Cipher is RC4-MD5
Server public key is 1024 bit
SSL-Session:
Protocol : SSLv3
Cipher : RC4-MD5
Session-ID: 5ED79B96790B5EEA2A35EC8343C9B9556ABEF2B467C8FD223ED7FE22F22D2DFF
Session-ID-ctx:
Master-Key: 7AEFB360BFB35D62BE141F13813723E99762B79A6A21FFF1C7D2E3D08773DEDCF668BBDE549172183E199A222B121400
Key-Arg : None
Start Time: 1068629748
Timeout : 300 (sec)
Verify return code: 19 (self signed certificate in certificate chain)
---
GET / HTTP/1.0 (★入力待ちになるので、HTTP リクエストをタイプし、Enter)
Host: www.verisign.co.jp (★Enter)
(★もう一度 Enter。すると、下記のようなレスポンスが返ってくる)
HTTP/1.1 200 OK
Date: Mon, 17 Nov 2003 20:37:45 GMT
Vary: Accept-language
Content-type: text/html
Connection: close
(略)

HTTP リクエストを送信する必要はなく、SSL/TLS のやりとりのみ確認したい場合は、標準入力を /dev/null で閉じてやればよい。
% openssl s_client -connect www.verisign.co.jp:443 < /dev/null
(略)

逆に、SSL/TLS は省略し、HTTP リクエスト・レスポンスを中心に見たい場合は、-quiet オプションをつけることで、表示が簡略化される。
% openssl s_client -connect www.verisign.co.jp:443 -quiet
depth=2 C = US, O = "VeriSign, Inc.", (略)
verify return:1
depth=1 C = US, O = Symantec Corporation, OU = Symantec Trust Network, (略)
verify return:1
depth=0 1.3.6.1.4.1.311.60.2.1.3 = US, 1.3.6.1.4.1.311.60.2.1.2 = Delaware, (略)
verify return:1
(ここから HTTP リクエストを入力すればよい)

サーバ側で SNI (Server Name Indication) を使っている場合は、-servername で目的の FQDN を指定する。
% openssl s_client -connect www.verisign.co.jp:443 -servername www.verisin.co.jp
なお、SNI とは、旧来の「IPアドレス1つにつき、SSL 証明書は1つしか扱えない」という制限を解消するために考案された SSL/TLS の拡張である。ちなみに似た目的のもとして SAN (Subject Alternate Names) というものもあるが、
  • SNI は、複数の証明書を 1つの IP アドレスで扱う仕組み
  • SAN は、1枚の証明書内に別名を付与する仕組み
であり、-servername オプションは SNI に対応したサーバに、
「私はこの FQDN に接続しようとしている」
ということを伝えるためのものである。

認証局の証明書を指定する場合、ファイル ca.crt を配置した上で、下記のように -CAfile オプションで指定する。
% openssl s_client -connect www.verisign.co.jp:443 -CAfile ca.crt

SSL/TLS プロトコルのバージョンを制限したい場合、下記を使う。
  • -ssl2 … SSLv2 のみを使って接続する
  • -ssl3 … SSLv3 のみを使って接続する
  • -tls1 … TLS 1.0 のみを使って接続する
  • -tls1_1 … TLS 1.1 のみを使って接続する
  • -tls1_2 … TLS 1.2 のみを使って接続する
  • -tls1_3 … TLS 1.3 のみを使って接続する
  • -dtls1 … DTLS 1.0 のみを使って接続する (DTLS は UDP でのセキュアな接続)
  • -dtls1_2 … DTLS 1.2 のみを使って接続する
SSLv3 を使って接続する例は下記。このサーバは現在使用が推奨されていない SSLv2・SSLv3 には対応していないようなので、接続することができない。
% openssl s_client -connect www.verisign.co.jp:443 -ssl3
(略)
no peer certificate available
(略)

逆に、特定プロトコルを使わないようにしたい場合、下記を使う。
  • -no_ssl2 … SSLv2 を使用せずに接続する
  • -no_ssl3 … SSLv3 を使用せずに接続する
  • -no_tls1 … TLS 1.0 を使用せずに接続する
  • -no_tls1_1 … TLS 1.1 を使用せずに接続する
  • -no_tls1_2 … TLS 1.2 を使用せずに接続する
  • -no_tls1_3 … TLS 1.3 を使用せずに接続する
-ssl2・-ssl3 などと異なり、-no_* は複数指定することができる。
% openssl s_client -connect www.verisign.co.jp:443 -no_ssl2 -no_ssl3
(略)
SSL-Session:
Protocol : TLSv1.2
(略)
→ この例では TLS 1.2 で接続したようだ

openssl speed … アルゴリズム速度を計測する
例えば DES (CBC)、DES-EDE3 (3DES。鍵 3つ)、AES の速度を計測してみよう。
% openssl speed des des-ede3 aes
(略)
Doing des cbc for 3s on 16 size blocks: 1978236 des cbc's in 2.96s
Doing des cbc for 3s on 64 size blocks: 519648 des cbc's in 2.99s
Doing des cbc for 3s on 256 size blocks: 131591 des cbc's in 3.00s
Doing des cbc for 3s on 1024 size blocks: 32823 des cbc's in 2.98s
Doing des cbc for 3s on 8192 size blocks: 4129 des cbc's in 3.00s
(略)
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
des cbc          10694.31k    11124.45k    11238.52k    11264.12k    11280.94k
des ede3          4114.52k     4174.61k     4195.20k     4208.62k     4212.41k
aes-128 cbc      14623.16k    15035.19k    15213.69k    15248.49k    15250.12k
aes-192 cbc      12625.59k    12986.96k    13248.40k    13200.37k    13245.66k
aes-256 cbc      11204.07k    11453.80k    11569.18k    11590.68k    11598.09k

1行目は、DES による暗号化を 16バイトのデータに対して 3秒間実行したところ、1978236 回実行できたことを表す。最後に表示される表を見ると、AES 128 ビットが最速で、DES と AES 256 ビットがほぼ同じ速度、DED-EDE3 (3DES) は DES の 3倍近く遅いことがわかる。

openssl rand … ランダムデータを生成する
100 バイトのランダムデータを生成し、file に出力:
% openssl rand 100 > file
10バイトのランダムデータを生成し、16進数文字列として出力:
% openssl rand -hex 10
dad81005165c675b498e
10バイトのランダムデータを生成し、BASE64 化して出力:
% openssl rand -base64 10
uEKHyWtH/cn13Q==

file にはバイナリデータが格納される。バイナリデータではなく、ランダムな文字列の数値を得たい場合は jot を使うとよい。
他にも、いろいろなランダム・乱数の生成方法を下記にまとめているので、一読いただきたい。

openssl version … openssl コマンドのバージョンを出力する
openssl version で、その環境の openssl のバージョンを出力することができる。-version や --version ではなく version であることに注意。
% openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013

Tips1. SSL/TLS 証明書の有効期限確認 2017/08/22 作成
リモートの SSL/TLS 証明書を有効期限を確認したい場合は、openssl s_client と openssl x509 を組み合わせる。servername オプションは SNI のためのものである。s_client の項を参照してほしい。
% openssl s_client -connect www.microsoft.com:443 -servername www.microsoft.com < /dev/null | openssl x509 -text | grep Not
Not Before: Apr 7 00:00:00 2017 GMT
Not After : Apr 8 23:59:59 2019 GMT
→ この例では、2017/04/07 00:00:00 (GMT) 〜2019/04/08 23:59:59 (GMT) の間は有効であることがわかる。
関連コマンド

p2cc Pascal コンパイラ

内部で p2c という、Pascal から C へのコンバータを呼び、その出力を C コンパイラでコンパイルしている。

passwd パスワードを変更する。

現在のパスワード、新しいパスワード、もう一度新しいパスワードの順で入力する。
% passwd
Changing local password for hogehoge.
Old password: (現在のパスワードを入力)
New password: (新しいパスワードを入力)
Retype new password: (確認のため、もう一度新しいパスワードを入力)
パスワードは 6文字以上、アルファベット以外の文字を含み、128文字以下 (FreeBSD-2.2.7の場合)。

なお、root が passwd コマンドを実行すると、現在のパスワードを入力する必要はない。
つまり root は誰のパスワードでも強制的に変更できるということである。
# passwd username (ユーザ username のパスワードを強制的に変更)
Changing local password for username.
New password: (新しいパスワードを入力)
Retype new password: (確認のため、もう一度新しいパスワードを入力)

passwd コマンドを実行すると、(BSD 系 UNIX では) /etc/master.passwd を更新し、pwd_mkdb コマンドが実行され、/etc/passwd などが更新される。
>> OSオンラインマニュアル(man) Linux passwd(5)
>> OSオンラインマニュアル(man) Linux passwd(1)
>> OSオンラインマニュアル(man) FreeBSD passwd(1)
>> OSオンラインマニュアル(man) Solaris10 passwd(1)

patch パッチを当てる

「パッチ」とは、古いファイルと新しいファイルの差分のことで、「パッチを当てる」とは、古いファイルと差分データを参照しながら新しいファイルを作ることを指す。

パッチファイルを入手し、
% patch < パッチファイル
とすると自動的にパッチ当て作業が行われる。オリジナルのファイルは、.orig という拡張子を付けたファイルに保存される。ただし、patch に慣れていない場合は、カレントディレクトリをどこにするかに迷うであろう。カレントディレクトリが違うとパッチ当てに失敗するからである。

パッチファイルの先頭部分を見てみると、
*** file.txt.org Sun Sep 12 09:53:17 1999
--- file.txt Sun Sep 12 09:53:17 1999
や (これは context 形式)、
--- file.txt.org Sun Sep 12 09:53:17 1999
+++ file.txt Sun Sep 12 09:53:17 1999
となど (これは unified 形式)、ファイル名の情報が記録されているはずである。この例はディレクトリ名はなく、ファイル名のみが記録されているので、パッチを当てる対象の file.txt が置いてあるディレクトリに移動してからパッチを当てるとよい。例えば
--- src/file.txt.org Sun Sep 12 09:53:17 1999
+++ src/file.txt Sun Sep 12 09:53:17 1999
なら、src ディレクトリの中ではなく、その一つ上に移動してからパッチを当てる。つまり、
% ls 「パッチの先頭に書かれているファイル名」
として、ファイル名が表示されるようなディレクトリに移動してからパッチを当てなければいけない、ということである。

次にパッチを当てる際の出力について解説する。
% patch < patch.txt
Hmm... Looks like a unified diff to me...
これは、パッチの種類を判別している。パッチにはいくつか種類があるが、普通 unified 形式か、context 形式が使われる (詳細は diff コマンドの項を参照)。つまり、
Hmm... Looks like a unified diff to me...
Hmm... Looks like a new-style context diff to me...
いずれかの出力ならば問題はない。しかし
Hmm... Looks like a normal diff to me...
のように、unified 形式でも context 形式でもない場合は、パッチ自体にファイルの情報が含まれていないので、パッチを当てるファイルを入力しなければならない。おそらくパッチ作成者のミスであろう。もし、
File to patch:
いう出力があった場合は、ユーザはパッチを当てるファイル名を入力するよう求められている。これは
  • パッチが context 形式でも unified 形式でもないので、どのファイルにパッチを当てたらよいのかわからない。
  • ファイルが見付からない (あるいはあなたの手元には、本当にパッチを当てるべきファイルが無いのかもしれない)。
という原因が考えられる。ファイルが見付からない場合、先に書いたようにパッチファイルに記録されたファイル名を見て、カレントディレクトリを移動しなければならない。

リバースパッチ
Reversed (or previously applied) patch detected! Assume -R? [y]
という出力があった場合は、
  • リバースパッチである
  • 既にそのパッチは当ててある
のいずれかである。diff コマンドでパッチを作る際、ファイルの引数を逆にしてしまうと、リバースパッチと呼ばれる正反対のパッチが作成される。これが原因ならば、
Assume -R? [y]
のところで「y」かリターンキーをタイプすると、リバースパッチとみなしてパッチを当てる。あるいは、あなたが過去にそのパッチを当てていることを忘れてしまい、再度同じパッチを当てようとしているかもしれない。その場合は「y」を選ぶと過去のバージョンに戻ってしまう。

オプション
-C 処理内容を表示するが、実際にはパッチを当てない。
まず最初はこのオプションを付けて実行すること。
-R パッチをリバースパッチと見なす。
最初からリバースパッチとわかっている場合は、-R オプションを付けることで
Reversed (or previously applied) patch detected! Assume -R? [y]
という問い合わせをせずに、パッチ当て作業を自動的に行う。
-N リバースパッチと思われるパッチをスキップする。

余談
なお patch コマンドは、パッチファイルの最初や最後にゴミが含まれていても自動的にスキップしてくれるので、NetNews のヘッダや、先頭にパッチの説明が入ったファイルでも気にせずパッチが当てられる。また、パッチ全体にインデントが付いていても自動的に認識する。さすがは Larry Wall (Perl の作者) が作ったプログラム。便利だ。

パッチファイルを作成するには diff を使う。
>> OSオンラインマニュアル(man) Linux patch(1)
>> OSオンラインマニュアル(man) FreeBSD patch(1)

pedal きれいな画像を描く

perl 高機能プログラミング言語。awk・sed・C などの便利なところだけを引き継いだ。

一般的には
#!/usr/local/bin/perl
print "Hello,world.\n";
というファイル (例えば sample.pl) を作り、
% chmod +x sample.pl
として実行権限を付け、
% ./sample.pl
として実行する。いわゆる perl4 (ver.4) と perl5 (ver.5) があるので、perl4 で動かなかったスクリプトは perl5 で試してみるとよい。

FreeBSD 2.x では、標準配布物として perl4 が /usr/bin/perl にインストールされる。port/package から perl5 をインストールすると /usr/local/bin/perl に実行ファイルが置かれる。

FreeBSD 3.x 以降は システム標準の perl (/usr/bin/perl) が perl5 になっており、perl4 は使われていない。

FreeBSD 5.0 以降は、perl5 が標準配布物ではなくなり、/usr/bin/perl が削除された。port/package から perl5 や perl5.8 などを好きなバージョンを選択してインストールするとよい。

なお、perl のバージョンは perl -v で確認できる。

perl は正規表現が強力なので、sed や tr の代わりに使うと便利である。
% tr a b < file
% tr '\015' \012' < file
% sed 's/abc/def/g' < file
% sed 's/\([ad]\).\([cf]\)/\1X\2/g' < file
は、それぞれ
% perl -pe 's/a/b/g' < file
% perl -pe 's/\015/\012/g' < file
% perl -pe 's/abc/def/g' < file
% perl -pe 's/([ad]).([cf])/$1X$2/g' < file
と書くことができる。また、
% perl -pi.bak -e 's/foo/bar/g' file
で、元のファイルを file.bak という名前で保存し、file を直接書き換える。
% perl -pi.bak -e 's/foo/bar/g' *.html
と複数のファイルを指定することもできる。

phone 高機能 talk。日本語(かな文字)を表示することができる

-ca ascii モード。talk と同じで英数字しか表示できない
-cj jis でかなを表示
-ce euc でかなを表示
-cs sjis でかなを表示

ping 指定のホストとのパケットの送受信ができるかを調べる

引数にホスト名や IP アドレスを指定すると、ping は相手先に ICMP echo というパケットを送信する。それに対して相手先が ICMP echo reply という応答パケットを送り返してくる。これを受信することで、ネットワークに問題がないか、遅延は発生していないか、などを調べることができる。

BSD や Linux の ping は、(応答があろうとなかろうと) 1秒おきに ICMP echo を送信し続け、ICMP echo reply が届くたびに往復時間などの情報を表示する。
% ping www.jp.freebsd.org
PING www.jp.freebsd.org (211.14.6.244): 56 data bytes
64 bytes from 211.14.6.244: icmp_seq=0 ttl=51 time=17.334 ms
64 bytes from 211.14.6.244: icmp_seq=1 ttl=51 time=16.747 ms
64 bytes from 211.14.6.244: icmp_seq=2 ttl=51 time=17.144 ms
64 bytes from 211.14.6.244: icmp_seq=4 ttl=51 time=14.234 ms
^C
⇒ 永遠に送信と応答を続けるので、適当なところで Ctrl-c で中断する。すると以下のようなサマリが表示される。

--- www.jp.freebsd.org ping statistics ---
4 packets transmitted, 3 packets received, 25% packet loss
⇒ 4パケット送信し、そのうち3パケット分の応答を受信。25% のパケットが喪失した。
round-trip min/avg/max/stddev = 14.234/16.364/17.334/0.318 ms
⇒ 往復時間の最小は 14.234ミリ秒、平均は 16.364ミリ秒、最大は 17.334秒、分散は 0.318 であった
上記の例では、icmp_seq=3 に対する応答が届かなかったことに注目しよう。また、「time=... ms」の部分を見ることで往復時間の多寡やばらつきを知ることができる。

Solaris の ping は、応答が返ってくると
% ping www.jp.freebsd.org
www.jp.freebsd.org is alive
というあっさりとした表示を出力してすぐに終了する。BSD や Linux のような挙動をさせるには -s オプションを指定する。

オプション
-c 回数 パケットを送受信する回数を指定する。指定しない場合は永遠にパケットを送り続ける。
-o 応答パケットをひとつだけ送信したら、終了する。
-t 秒数 指定時間が経過したらタイムアウトする。BSD や Linux の ping のデフォルトは、タイムアウトなしである (永遠に送信しつづける)。Solaris の ping のデフォルトは 20秒。
-i 秒数 パケットを送信する間隔を指定する。デフォルトは 1秒。Solaris では -i ではなく -I オプションを使う。

シェルスクリプトで特定のホストに到達できるかを調べるには、以下のようにするとよいだろう。
host=www.exmaple.com
timeout=10
ping -t $timeout -o $host
if [ $? != 0 ]; then
echo "$host に接続できません (タイムアウトまでの秒数 $timeout)"
fi

トラブルシュート
まず、ping を目的のマシンに打ってみる。
% ping www.example.com
ping: cannot resolve www.example.com: Unknown host
このエラーが出たときは、DNS サーバによる「ホスト名→IP アドレス」の変換がうまくいっていないということである。原因としては、
  • 相手側の DNS サーバが落ちている
  • こちら側の DNS サーバが落ちている
  • /etc/resolv.conf、/etc/hosts などの設定ミス
が考えられる。

もし www.example.com に対応する IP アドレスを知っているなら、直接 IP アドレスを指定してみる。
% ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1): 56 data bytes
36 bytes from 127.0.1.1 (127.0.1.1): Destination Host Unreachable
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 5400 051a   0 0000  f0  01 b735 133.8.2.77  10.0.0.1

最近は、ping が使用する ICMP echo をファイアウォールでフィルタリングしたり、OS が ICMP echo reply を送信しないよう設定するケースも増えている。例えば、www.yahoo.co.jp に ping を打っても、応答は返ってこない。

ping という名前は、潜水艦が海中で音を発し、音の反射によりまわりの状況を知ることからきている。「ピング」でなく「ピン」と発音する。
>> OSオンラインマニュアル(man) Linux ping(8)
>> OSオンラインマニュアル(man) FreeBSD ping(8)

pkgadd パッケージのインストール。Solaris のみ。

パッケージをインストールする Solaris 用コマンド。

Solaris にフリーソフトをインストールするには、SunSite (例えば http://sunsite.sut.ac.jp/sun/solbin/)からバイナリを選択し (OS のバージョン・Solaris/Intel の違いに注意)、ダウンロードして、
% gunzip foo-sol8-sparc-local.gz
と伸長すると、foo-sol8-sparc-local というファイルができるので、root になって
# pkgadd -d ./foo-sol8-sparc-local
とする。

FreeBSD では pkg_add コマンドを使う。
>> OSオンラインマニュアル(man) Solaris10 pkgadd(1M)

pkg_add パッケージのインストール。FreeBSD のみ。

FreeBSD のアプリケーションの管理には、ports と packages という仕組みを使うと便利である。

UNIX のプログラムのほとんどはソースファイルで配布されている。そのソースを取得して FreeBSD 上でコンパイルしてもよいのだが、
  • 開発者が FreeBSD を持っていないため、コンパイルできるかどうか確認されていない。
  • FreeBSD のバージョンアップに伴い、ライブラリが変更された
  • OS 依存のライブラリ関数などを使用している
などの理由で、FreeBSD ではうまくコンパイルできないことがある。大抵の場合、ソースを数行変更するだけでコンパイルできるが、経験がないと難しいだろう。

そこで、ソース変更の部分を自動化する ports というシステムが考えられた。ports は
  • ソースファイルのある場所 (URL)
  • FreeBSD でうまくコンパイルできるようにするためのパッチ
を集めたものである。

パッケージ (package) とは、ports を使ってコンパイルしたバイナリのことである。ファイル形式はただの tarball (tar アーカイブを gzip で圧縮したもの) で、アプリケーション foo のバージョン 1.2.3 は foo-1.2.3.tgz というファイル名で配布される。

これらのパッケージは CD-ROM や、ftp://ftp.jp.freebsd.org/pub/FreeBSD/FreeBSD-current/packages/All/などに置かれている (これは current のパッケージなので、バージョンの違いに注意)。
% tar ztvf foo-1.2.3.tgz
とすればわかるが、必要なバイナリや設定用ファイルに加えて、+CONTENTS、+COMMENT、+DESCなどの + から始まるファイルが同梱されている。これらのファイルの意味は
  • +CONTENTS … どういうファイルをどこにどのようなパーミッションで書き込むか
  • +COMMENT … パッケージの簡単な説明
  • +DESC … パッケージの詳細な説明
となっている。他にもパッケージによっては
  • +REQUIRED_BY … このパッケージに依存しているパッケージ名
  • +INSTALL … パッケージをインストールする際に実行されるスクリプト
  • +DEINSTALL … パッケージを削除する際に実行されるスクリプト
がある。

パッケージをインストールするには pkg_add コマンドを使う。root になって
# pkg_add foo-1.2.3.tgz
と、引数にパッケージ名を指定すれば、必要なファイルが自動的にインストールされる。CD-ROM からだと
# pkg_add /cdrom/FreeBSD-3.4/packages/All/foo-1.2.3.tgz
となるだろう。すると、pkg_add はパッケージの中の +CONTENTS を参照しながら、ファイルを指定の場所に展開する。もし +INSTALL があればそれを実行する。

インストールした後には、(csh・tcsh を使っているなら) rehash コマンドでハッシュテーブルの再構築をしておこう。

-n 実際には何も書き込まず、報告のみをする
-v 全ての情報を表示

Solaris にもパッケージシステム (FreeBSD とは互換性がない) があるが、こちらは pkgadd コマンドを使う。
>> OSオンラインマニュアル(man) FreeBSD pkg_add(1)

pkg_delete パッケージの削除。FreeBSD のみ

インストールされているパッケージを削除する。現在インストールされているパッケージの情報は /var/db/pkg に置いてある。

パッケージ foo-1.2.3 を削除したい場合は
# pkg_delete foo-1.2.3
とする。すると /var/db/pkg/foo-1.2.3/+CONTENTS を元に、関連するファイルを削除し、/var/db/pkg/foo-1.2.3 も消去される。

-n 実際には何も書き込まず、報告のみをする
-v 全ての情報を表示

tcsh を使っている場合、
% complete pkg_delete n@*@'`\ls -1 /var/db/pkg`'@
と設定することで、pkg_delete の補完が便利になる。
>> OSオンラインマニュアル(man) FreeBSD pkg_delete(1)

pkg_info パッケージの情報を表示。FreeBSD のみ

-a 現在インストールされているパッケージの情報を表示
-aI -aよりも詳しい情報を1行で表示
-c 1行の簡単な説明を表示
-d 数行の簡単な説明を表示
-e パッケージ名 パッケージがインストールされていれば0を、そうでなければ1を返す
-L インストールされるファイル名を表示
-v 全ての情報を表示
>> OSオンラインマニュアル(man) FreeBSD pkg_info(1)

playmidi MIDIプレイヤー。FreeBSDでは音が悪いという噂がある。

pngquant PNG ファイル容量・ファイルサイズ圧縮ツール

pngquant コマンドは画像フォーマット PNG を減色することで、ファイル容量削減・ファイルサイズ縮小する圧縮ツールである。画質にうるさくない人が見ても、元のファイルとの違いをほぼ感じ取ることはできないであろう。UNIX/Linux に加え、Windows版・MacOS 版も提供されている。TinyPNG などの圧縮サービスはあるが、画像ファイルが手元に大量にある場合、コマンドラインからの一括圧縮ツールとして使うとよい。


pngquant コマンドの基本的な使い方
pngquant コマンドの基本的な使い方は下記のとおりである。
% pngquant image.png
→ image-fs8.png というファイルが生成される (元ファイルが残る)。
% pngquant *.png
→ 複数ファイルについて [元画像ファイル名]-fs8.png というファイルが生成される。
% pngquant dir/*.png
→ dir/ の下に、[元画像ファイル名]-fs8.png というファイルが生成される。
% pngquant --ext .png --force *.png
→ 元ファイルと同じファイル名で保存する (元ファイルは残らない)

いろいろパラメータをいじって画質確認するなど試行錯誤したいときは、カレントディレクトリに *.png を置き、newpng/ ディレクトリを作成した上で、
% ls *.png | sed 's|\(.*\)|pngquant --force -o newpng/\1 \1|'
pngquant --force -o newpng/img1.png img1.png
pngquant --force -o newpng/img2.png img2.png
pngquant --force -o newpng/img3.png img3.png
などと確認した上で、最後に "| sh" を付けて
% ls *.png | sed 's|\(.*\)|pngquant --force -o newpng/\1 \1|' | sh
で実行するのはどうかと提案する次第である。

PNG 画像圧縮の仕組み
PNG 画像はトゥルーカラーとして 24bit (1677万色) または 48bit (280兆色) のカラーを選択できるが、ほとんどのケースではそれほど多くの色を使うわけではない。一方、PNG にはインデックスカラーという、8bit (256色) だけを使うモードがある。

pngquant コマンドは、24bit または 48bit の画像を 8bit のインデックスカラーに減色するものである。また、インデックスカラーには 16色・4色・2色のパターンもあるので、可能であればそれらのより小さい色数に減色できないか試みる。

しかし単純に減色した場合、画像が汚く見えてしまうので、ディザリングという少ない色数で多くの色が存在するかのように見せる方法を使う (例えば、青と赤のドットを交互に置くと紫に見えるというのがディザリング)。pngquant のデフォルトでは「フロイド-スタインバーグ・ディザリング」という手法を使うが、対象画像により相性があるので (多分)、「オーダード・ディザリング」という手法を使うこともできる。

pngquant コマンドのオプション一覧
pngquant コマンドのオプション一覧を以下に示す。画質に関わるオプションとして、--floyd・--posterize・--quality・--speed があり、それぞれがどう機能するか大変わかりづらい。画質にうるさくない当ページ管理人の意見としては、「どうせ判別できないんだからデフォルトでいいんじゃない?」であるが、こだわりのある方は pngquant コマンドが使用している libimagequant というライブラリのマニュアルやソースを読んでいただきたい。

▷ --force
出力ファイルがすでに存在する場合、pngquant コマンドは警告を出してスキップするが、--force オプションを付けると上書きする。
▷ --ext [拡張子等]
--ext -new.png などとすると、image.png が image-new.png として保存される。
▷ --floyd [数字]
フロイド-スタインバーグ・ディザリングにおけるディザリングレベルを指定する。0〜1 の範囲で指定可能で、デフォルトは 1。0 は指定しない。--floyd 0.5 などと指定する。
▷ --iebug
IE6 における透過 PNG の表示バグに対応した画像を生成する。
▷ --nofs
ディザリング時に、フロイド-スタインバーグ・ディザリングを使わない。結果として、オーダード・ディザリングが使用される。この場合、デフォルトのファイル名は"-fs8.png" ではなく "-or8.png" となる。
▷ -o [出力ファイル名] または --output [出力ファイル名]
出力ファイル名を指定する。
% pngquant *.png
などと複数ファイルを対象として圧縮する場合、本オプションは使用できない。
▷ --posterize [数字]
画像ビット数を切り捨てる。[数字] には 0〜4 を指定可能で、0 はデフォルト (=切り捨てない)、1〜4 と数が大きくなるほど切り捨てビット数が多くなる。その分、画質は悪くなる。
▷ -Q [最小-最大] または --quality [最小-最大]
JPEG 圧縮率のような画質を 0〜100 で指定する。デフォルトは 100 (最高画質) である。
% pngquant --quality 0-50
% pngquant --quality 80-100
▷ --skip-if-larger
圧縮したファイルが元ファイルよりファイルサイズが大きい場合、そのファイルを生成しない。
▷ --strip
出力ファイル生成時に、元ファイルに含まれるメタデータをコピーしない。
▷ -s [数字] または --speed [数字]
圧縮スピードを 1〜11 を指定できる。1 が高圧縮率かつ最も遅く、11 が低圧縮だが速い。標準は 3 であるが、3 と比べると 10 の場合は 5% 画質が落ちるが 8倍速いとのこと。なお、11 はディザリングが無効になる。

popclient POPクライアント。

POP サーバからメールをダウンロードするプログラム。popclient は開発終了し、後継の fetchmail の開発が続いている。

PPP でプロバイダに接続している場合、telnet でログインしてメールを読むのでもいいが、メールを読んでいる間も電話代がかかる。popclient を使うと、プロバイダのPOPサーバからメールを取ってきて、自分のホストにメールが届いたかのようにすることができる。

オプション:
-2 POP2プロトコルを使う (普通は POP3 プロトコルを使う)
-3 POP3プロトコルを使う
-a 既に一度ダウンロードしたメールも含め、全てのメールをダウンロードする (POP3 のみ)
-c ダウンロードしたメールを標準出力に書き出す
-k ダウンロード後メールサーバにあるメールを消去しない
-K ダウンロード後メールサーバにあるメールを消去する
-o folder 取ってきたメールを保存するフォルダ名
-u user メールサーバでのユーザ名
-p passwd メールサーバでのパスワード
-r folder メールサーバのフォルダ名

実際に使うには
% popclient -3 -K -u username -p password
などとすればよい。username と password は、POP サーバのアカウント名/パスワードである。

povray レイトレーシングツール (3D 画像作成ツール)

POV-Ray は 3次元画像を生成するツールである。

ppp ダイヤルアップ PPP 接続する

primes 素数を調べて表示

ある数字を指定すると、その数字より大きい素数を表示する
% primes 123456
123457
123479
123491
:
:
FreeBSD では /usr/games/primes にインストールされるので注意。

printenv 現在設定されている環境変数を表示。

指定された環境変数を表示する。引数を省略すると、現在設定されている全ての環境変数を表示する。
>> OSオンラインマニュアル(man) Linux printenv(1)
>> OSオンラインマニュアル(man) FreeBSD printenv(1)

printf C の printf(3) と同じような出力を行うコマンド (8進数/10進数/16進数変換)

C の printf(3) と同じような出力をコマンドラインから行うことができる。

% printf "abc\n"; printf "def\n"
abc
def
⇒ echo と異なり、改行させたければ明示的に \n を付ける必要がある。
% printf "abc"; printf "def"
abcdef
⇒ \n を付けないとこうなる
% printf "HOME=[%s]\n" $HOME
⇒ 文字列を表示するには %s を使う
% printf "HOME=[%s] USER=[%s]\n" $HOME $USER
⇒ 複数のフォーマットも指定できる
% printf "[%d]\n" 30
[30]
⇒ 数値は %d を使う (この例では %s でも同じ)
% printf "[%5d]\n" 30
[ 30]
⇒ 5桁で右詰め
% printf "[%-5d]\n" 30
[30 ]
⇒ 5桁で左詰め
% printf "[%05d]\n" 30
[00030]
⇒ 5桁でゼロパディング

8進数/10進数/16進数変換
printf を活用し、8進数・10進数・16進数の変換を行うことができる。
printf "%d\n" 0x10
⇒ 16進数を 10進数に
printf "%d\n" 010
⇒ 8進数を 10進数に
printf "%x\n" 10
⇒ 10進数を 16進数に
printf "%x\n" 010
⇒ 8進数を 16進数に
printf "%o\n" 0x10
⇒ 16進数を 8進数に
% printf "%o\n" 10
⇒ 10進数を 8進数に

より単純な出力だけでよいなら echo コマンドを使うとよい。ほとんどのシェルでは組み込みコマンドとして実装されているので、printf コマンドに比べて高速である。

より詳細な printf 書式は、ライブラリ関数 printf の項を参照してほしい。
>> OSオンラインマニュアル(man) FreeBSD printf(1)
>> OSオンラインマニュアル(man) Linux printf(3)
>> OSオンラインマニュアル(man) Linux printf(1)

priocntl プロセスのスケジューリングポリシーをセット

priocntl は Solaris のコマンド。

procmail メール自動処理プログラム

特定の宛先、特定のサブジェクト、特定の内容などに応じて自動的にメールを処理させることができる。まず ~/.forward に
"|exec /usr/local/bin/procmail"
などと procmail のフルパスを記述しておく。必ず両端を "" で囲むこと。これでメールが届くと procmail が自動的に起動されるようになる (一部の Linux では~/.procmailrc が存在すると、メール到着時に勝手に procmail が起動されるように /etc/sendmail.cf が設定されているようだ)。

次に ~/.procmailrc に
LOGFILE=$HOME/procmail.log
:0
* ^From:.*hoge
! foo@bar.com
と書いておく (このファイルをレシピと言う)。これでメールの From フィールドに「hoge」という文字列が含まれるメールは、自動的に foo@bar.com に転送される。条件にマッチしないメールは通常通りメールスプール (/var/mail/$USER や /var/spool/mail/$USER など) に追加される。

もし希望通り動作しなかった場合は、レシピの LOGFILE で指定した ~/procmail.log を見よう。エラーになった原因などが書かれているはずである。もし何も書かれていなかったら、~/.forward の記述を見直すこと。また、ログファイルを見ても原因がわからない場合は
VERBOSE=on
LOGFILE=$HOME/procmail.log
とすることでより詳細な情報がログファイルに記録される。

レシピには上記のように
:0 [フラグ] [:ロックファイル]
* 条件
動作
という書式を連続して書くことで、複雑な動作をさせることができる ([] 内は省略可能)。以下に少し突っ込んだ使い方を示す。

サブジェクトに「hoge」を含むメールを command の標準入力に渡す。
:0
* ^Subject:.*hoge
| command
サブジェクトが(「hoge」を含む場合でなく)「hoge」であった場合だけ動作させたいなら、
:0
* ^Subject: hoge$
| command
とすればよい。また、メールが連続して届いたときに command が同時に起動されては困るなら、
:0 :
* ^Subject: hoge$
| command
と「:0」の後に「:」を付けることで、procmail に排他処理 (ロック処理) を行うよう指示することができる。この場合は「:」の後にロックファイル名を省略したので、procmail が勝手にロックファイル名を決めてくれる。

メールをリファイルすることもできる。メールスプールのような1つのファイルに複数のメールを格納する mbox 形式と、MH や Mew のような1つのメールにつき1つのファイルを使う MH 形式を選択できる。

mbox 形式は、レシピを
MAILDIR=$HOME/Mail
:0 :
* ^Subject: \[FreeBSD\-users\-jp \d+\]
FreeBSD-users-jp
とすることで、Subject が [FreeBSD-users-jp \d+] にマッチしたメールが
$HOME/Mail/FreeBSD-users-jp
というファイルにどんどん追加されていく (存在しなければ新規作成される)。

一方、MH 形式は
MAILDIR=$HOME/Mail
:0 :
* ^X-Sequence: FreeBSD\-users\-jp \d+
FreeBSD-users-jp/.
と最後に「/.」を付けることで、$HOME/Mail/FreeBSD-users-jp という *ディレクトリ* の下にメールが保存される。メールの番号は届いた順に1番から付けられ、
  • $HOME/Mail/FreeBSD-users-jp/1
  • $HOME/Mail/FreeBSD-users-jp/2
  • $HOME/Mail/FreeBSD-users-jp/3
と順に作成されていく。なお、メーリングリストの配送メールを振り分ける場合は、上記のように Subject によって振り分けるのではなく、X-Sequence や X-Ml-Name ヘッダを参照することをお勧めする。

ここで転送しつつリファイルするレシピを書いてみよう。
MAILDIR=$HOME/Mail
:0
* ^Subject: .*hoge
{
:0 c
! foo@bar.com

:0
hoge
}
このように { } で囲むことでブロックを作成することができる。2番目と3番目には「*」で始まる条件文が書いていないので、常に実行されることになる。「:0 c」の「c」は、
その条件に適合した場合、メールのコピーを作成し、以後のレシピに渡す
という意味のフラグである。

次に、1番目の条件にマッチしたものだけ特定のメールアドレスに転送し、マッチしなかったものだけ別のメールアドレスに転送する例をあげる。
:0
* ^Subject: .*hoge
! foo@bar.com

:0 E
! fuga@bar.com
Eフラグは「前のレシピにマッチしなかった場合」、つまり「ELSE IF」という意味を持つので、Subjectに「hoge」を含むメールは foo@bar.com に転送されて、そうでないメールは fuga@bar.com に転送されることになる。ただし、1番目の条件にマッチしたものは、特に定義しない限りその次の条件にはマッチしないので、上記レシピは
:0
* ^Subject: .*hoge
! foo@bar.com

:0
! fuga@bar.com
と等価である。

~/.procmailrc のパーミッションは 644 か 600 にしておくこと。664 だと、procmail が「セキュリティが甘い」と判断して、エラーとなる環境もある。その場合は /var/log/maillog など sendmail のログにエラーメッセージが吐かれる。
(参考: UNIX MAGAZINE 1998年10月号 P.36 「UNIX知恵袋42」 島 慶一)

ps 実行中のプロセスの情報を表示

以下の情報は FreeBSD を元にしたものである。Linux や Solaris などとはオプションの構成が全く違う。BSD 系だと、自分のプロセスを見るには ps 、システム全体のプロセスを見るには ps ax、もっと詳細なものは ps aux を使う。Solaris などの SystemV 系だと、それぞれ ps、ps -ef となる。

あるプロセスの状態を見るため、
% ps ax | grep hogehoge
とすると、
483 ?? I 0:00.07 /usr/bin/hogehoge
3094 p2 S+ 0:00.01 grep hogehoge
と、grep 自身のプロセスまで表示されることがある。それを防ぐには
% ps ax | grep hogehoge | grep -v hogehoge
や、
% ps ax | grep '[ h]ogehoge'
とするとよい。

以下は BSD 系のオプション。
-a 他ユーザが実行したプロセスも表示
-e 各プロセスが reference (?)している環境変数を表示
-j 各プロセスの詳細な情報を表示
(user pid ppid pgid sess jobc state tt time command)
-m メモリの使用量でソートする
-p num 指定したプロセスIDの情報を表示
-r CPUに使用量でソートする
-u 各プロセスの詳細な情報を表示 (SystemV の -u は BSD の -U と同じ)
(user pid %cpu %mem vsz rss tt state start time command)
-U user 指定ユーザが実行したプロセスを表示
-v 各プロセスの詳細な情報を表示
-w 1行132桁で表示する
デフォルトでは、端末の横幅に応じて出力幅がカットされるので、表示されない部分が出てくる可能性がある。そのため
% ps aux | grep hoge
としても、意図したプロセスを表示できないことがある。また、-ww とすると、必要なだけ横幅を広げる。

%CPU CPUの使用率
%MEM メモリの使用率
ACFLAG
COMMAND
CPU
FLAGS
INBLK
JOBC
KTRACE
KTRACEP
LIM
LOGNAME
LSTART
MAJFLT
MINFLT
MSGRCV
MSGSND
NICE
NIVCSW
NSIGS
NSAWP
NVCSW
NWCHAN
OUBLK
PGID
PID プロセスID
PPID 親プロセスID
PRI
RSS
SESS
STAT
STARTED プロセスの開始時刻
TIME
TT 端末名
UID ユーザID
USER プロセスを実行したユーザ名
VSZ
WCHAN
>> OSオンラインマニュアル(man) Solaris10 ps(1)
>> OSオンラインマニュアル(man) FreeBSD ps(1)
>> OSオンラインマニュアル(man) Linux ps(1)

pwd カレントディレクトリを表示する。

詳しくは cd コマンドの項を参照してほしい。

pwd_mkdb パスワードファイルを作成する

本来のパスワードファイルは /etc/master.passwd にあり、これは root しか見ることはできない。/etc/master.passwd から暗号化されたパスワードなどを取り除いたものが /etc/passwd で、これは誰でも見ることができる。また、/etc/pwd.db と /etc/spwd.db というファイルがあり、これらはデータベース化されている(テキスト形式ではない)。

/etc/passwd・/etc/pwd.db・/etc/spwd.db は、/etc/master.passwd から作成することができる。3つのファイルが壊れても、/etc/master.passwd さえ残っていれば、
# pwd_mkdb /etc/master.passwd
で、/etc/pwd.db・/etc/spwd.db が作成され、
# pwd_mkdb -p /etc/master.passwd
で、/etc/passwd が作成される。

python 汎用的なプログラミング言語

代入
num = 3
str = "abc"
str = 'abc'
数値計算
print 1 + 2 (加算)
print 3 - 1 (減算)
print 8 / 2 (除算)
print 8.0 / 3 (2.6666666666666665)
print 8.0 // 3 (除算時に切り捨て)
print 7 % 3 (7を3
print 3 ** 4 (3の4乗)
文字列
print 'abc'
print "abc"
→ シングルクォートでもダブルクォートでもいい。
print 'abc\ndef'
print "abc\ndef"
→ Perl や Ruby などは \n などのエスケープシーケンスを使えるのは "〜" のみであるが、Python ではシングルクォートでもダブルクォートでもどちらも使える。
print len('abc')

qkc 漢字コードを変換。改行コードを変換。

nkf と似たような書式を持つが、
% qkc -j file
とすると nkf とは違って、引数で指定したファイル自体を書き換える。ワイルドカードを使って
% qkc -j *.txt
とすると、各ファイルごとに変換を行う。

オプションは以下の通り。
-j JIS コードに変換
-s SJIS コードに変換
-e EUC コードに変換
-O nkf のように、変換済みコードは標準出力に書き出される
また、改行コードの変換もできる。
-m 改行コードを CR LF (MS-DOS の改行コード) に変換
-u 改行コードを LF (UNIX の改行コード) に変換
-ma 改行コードを CR (Mac の改行コード) に変換
-z ファイルの末尾についている ^Z を取り除く

UNIX → MS-DOS (SJIS、改行コードは CR LF)
% qkc -sm sample.unix > sample.msdos
MS-DOS → UNIX (JIS、改行コードはLF)
% qkc -ju sample.msdos > sample.unix
UNIX → Mac (SJIS、改行コードはCR)
% qkc -sma sample.unix > sample.mac
Mac → UNIX (JIS、改行コードはLF)
% qkc -ju sample.mac > sample.unix

quota ディスク割り当て状況を表示

UNIXには quota という、各ユーザごとに使用できるディスク容量を決めることができる。使用できるディスク容量の上限には、ソフトリミットとハードリミットがある。ユーザはハードリミット以上のディスクスペースは絶対に使うことができない。一方、ソフトリミットを越えてもファイルの作成はできるが、一定期間が過ぎるとログインを不可能にするなどの設定が可能。

例えば、ソフトリミットを 10MB、ハードリミットを 20MB、猶予期間を1週間に設定すると、10MB 以上ディスクスペースを使うとカウントダウンが始まり、1週間以内に 10MB を下回らないとログインできなくなる。また、20MB 以上のディスクスペースは決して使うことができない(ファイルを書き出そうとしても失敗する)。普通の UNIX では、デフォルトでは quota は設定されていない (デフォルトでは使いたい放題)。

一般的なプロバイダの「ディスク10MB使用可能」などというのは、quota を使って実現されているわけですな。
>> OSオンラインマニュアル(man) FreeBSD quota(1)
>> OSオンラインマニュアル(man) Linux quota(1)

rain 雨が降るデモ

X上ではなく、コンソール上で雨が振る。結構しょぼい。

rcp リモートホスト間でファイルをコピー

リモートホストからローカルホストへ、またはその逆の、ローカルホストからリモートホストへ、ファイル・ディレクトリをコピーすることができる。

ローカルのファイルは、普通通り指定すればよいが、リモートのファイルは
ログインネーム@ホスト名:ファイル名(ディレクトリ名)
という形式で指定する。

% rcp user@host:~/lib/sample .
⇒ リモートホスト host (ログインネーム user) の ~/lib/sample を、ローカルホストのカレントディレクトリにコピー (ファイルを持ってくる)
% rcp sample.txt user@host:/tmp
⇒ ローカルホストのファイル sample.txt をリモートホスト host (ログインネーム user) の/tmp にコピー (ファイルを置きにいく)
% rcp user@host:~/lib/\* .
% rcp "user@host:~/lib/*" .
⇒ リモートホストの ~/lib/ 以下のファイルをカレントディレクトリにコピー。ワイルドカードを使う場合は、シェルにワイルドカードを解釈されないようにエスケープしないといけない。上の例のように、「\」を使ってもよいし、全体を「"〜"」で囲ってもよい。

rcp は「リモート→ローカル」「ローカル→リモート」のファイル転送を行うコマンドだが、cp と同様に「ローカル→ローカル」なコピー機能もある。引数のファイル名に「:」が含まれていない場合、ローカル名ファイル名と見なされてしまう (「:」が含まれていても「/」の後にある場合も同様)。よって、
% rcp sample.txt user@host
とすると、一見リモートホストのホームディレクトリに sample.txt がコピーされるように思えるが、「user@host」に「:」が含まれていないため、ローカルのファイル名と見なされてしまい、ローカルホストのカレントディレクトリに user@host というファイルができてしまう。

rcp・rsh を使うには、リモートホストの ~/.rhosts に、ローカルホスト名とローカルホストでのユーザ名が記述されている必要がある。

rcp・rsh はセキュリティに少々問題がある。詳しくは ~/.rhosts で説明する。
>> OSオンラインマニュアル(man) Linux rcp(1)
>> OSオンラインマニュアル(man) FreeBSD rcp(1)
>> OSオンラインマニュアル(man) Solaris10 rcp(1)

readline 行入力支援ライブラリ

readline は、CUI アプリケーションにおいてユーザが行を入力する際に便利な「行頭・行末移動」「ヒストリ機能」などを提供するライブラリである。readline というコマンドがあるわけではない。

プログラム開発者が「行入力が面倒だけど、いちいちそういう機能を提供するのが面倒だから readline を使おう」と思って readline ライブラリを利用したら、利用者は readline の機能を享受できる。開発者が「readline なんか使わねぇよ」と考えたなら、利用者は仕方なく不便な行入力を行わなくてはならない。

一般的には、readline をソースからコンパイルしてインストールすると
  • /usr/local/lib/libreadline.so (と libreadline.a)
  • /usr/local/lib/libhistory.so (と libhistory.a)
にインストールされる (Linux や FreeBSD では標準配布物に含まれているので、/usr/lib/ などに置かれる場合が多い)。この状態で readline 対応アプリをコンパイルすると、大抵は configure した際に readline がインストールされているかチェックし、インストール済なら readline をリンク、インストールされていなければリンクしないような Makefile を生成する。

readline が提供する主な機能と、そのキーバインドは以下の通りである (ほとんどが emacs と同じ)。
  • 1文字戻る (Ctrl-b)
  • 1文字進む (Ctrl-f)
  • 行頭に移動 (Ctrl-a)
  • 行末に移動 (Ctrl-e)
  • カーソル位置から行末までを削除 (Ctrl-k)
  • 1行上 (直前に入力した内容) に移動 (Ctrl-p)
  • 1行下に移動 (Ctrl-n)
  • 逆方向インクリメンタルサーチ (Ctrl-r)
  • 補完・または候補一覧を表示 (TAB)
  • エスケープシーケンスを入力 (Ctrl-q・Ctrl-v)
なお、上記機能は readline を利用するプログラムによりカスタマイズが可能であることに注意。

.inputrc
readline の機能は、~/.inputrc というファイルに記述することで設定が可能である。

libedit
readline のライセンスが GPL であることを嫌い、NetBSD 界隈で readline 互換の libedit というライブラリが開発された。editline と表記することもある。

libedit は GPL ではなく BSD ライセンスとなっている。readline との互換性 100% が目標だが、libedit 独自の機能拡張もある。一部 tcsh の影響も受けているようだ。マニュアルは editline(3)・editrc(5)。

FreeBSD では readline と libedit の両方とも標準配布物に含まれている。FreeBSD 5.2.1-RELEASE では、bc コマンドが readline を、ftp コマンドが libedit を使用している。機能を比べてみるとおもしろしかもしれない。

reset 端末をリセットし、文字化けを解消する

reset コマンドは、端末をリセットするコマンドである。バイナリファイルを表示したりして端末が文字化けした場合、それを修復することができる。

Linux の場合、マニュアルには tput(1) に clear,rmacs,rmm,rmul,rs1,rs2,rs3 引数を付けて呼ぶ、とある。さらに terminfo(5) に、下記のようにある。要は、画面消去し、カーソルを左上に戻し、選択されているキャラクターセットを戻し(?)、メタモードをOFFにし、アンダーラインモードをOFFにし、3つのリセット的なものをすると、初期化できる、らしい。

Variable Booleans        CapName     TCap-Code   Description
----------------------------------------------------------------------------------
clear_screen             clear       cl          clear screen and home cursor (P*)
exit_alt_charset_mode    rmacs       ae          end alternate character set (P)
meta_off                 rmm         mo          turn off meta mode
exit_underline_mode      rmul        ue          exit underline mode
reset_1string            rs1         r1          reset string
reset_2string            rs2         r2          reset string
reset_3string            rs3         r3          reset string
>> OSオンラインマニュアル(man) Linux reset(1)

rev ファイル・文字列の 1行を逆順にする

rev コマンドは、ファイルや文字列に含まれる 1行の内容を逆順にするコマンドである。
% echo abcde | rev
edcba
→ 標準入力の内容を逆順に。
% cat file.txt
12345
67890
% rev < file.txt
54321
09876
→ ファイルからの例。ファイルの行自体の順序が変わるわけではない。

なんの役に立つのかと思ってしまうコマンドだが、役に立つときは役にたつ。sort コマンドと組み合わせることで、末尾からのソートができる。

ドメイン名のソート
下記のようなドメイン名のリストがあるとする。
www1.example.com
www-a.example-b.com
www1.example.net
www-b.example-b.com
www2.example.com
www2.example.net
これを見やすくしたいが、www1・www2 などのサブドメインではなく、example.com や example.net などのドメインでソートしたいとする。その場合、rev コマンドで逆順にし、ソートし、再度 rev コマンドで戻すとよい。
% cat foo.txt | rev | sort | rev
www-a.example-b.com
www-b.example-b.com
www1.example.com
www2.example.com
www1.example.net
www2.example.net

ファイル名拡張子でのソート
下記のようにファイル名について rev + sort + rev することで、拡張子単位でまとめることができる。
% find . -type f | rev | sort |rev
./file1.c
./dir/file2.c
./dir2file3.c
./header1.h
./header2.h
./dir2/header3.h
./text1.txt
./text2.txt
./dir/text3.txr
>> OSオンラインマニュアル(man) FreeBSD rev(1)
>> OSオンラインマニュアル(man) Linux rev(1)

realpath 相対パスを絶対パスに展開する

realpath コマンドは、相対パスを絶対パスに変換するコマンドである。また、以下の処理も行う。
  • シンボリックリンクをたどる
  • ../ や ./ を削除
  • // (/ を複数重ねる) を / に変換

要は、ファイル名の正規化を行うわけである。
% realpath ../
/usr/home/user
>> OSオンラインマニュアル(man) Linux realpath(3)
>> OSオンラインマニュアル(man) Linux realpath(1)
>> OSオンラインマニュアル(man) FreeBSD realpath(1)

reboot システムを再起動する

リブートする際は reboot コマンドを使ってもいいし、shutdown -r now でもいい。
>> OSオンラインマニュアル(man) Linux reboot(2)
>> OSオンラインマニュアル(man) Linux reboot(8)
>> OSオンラインマニュアル(man) FreeBSD reboot(8)
>> OSオンラインマニュアル(man) Solaris10 reboot(1m)

rehash ハッシュテーブルを再構築する。csh・tcsh の内部コマンド

csh や tcsh においてコマンドをタイプしたとき、実行可能ファイルを見つけるために、毎回 PATH で指定されたディレクトリを検索するわけではない。csh・tcsh はハッシュテーブルに実行可能なコマンドを登録し、そこからコマンドを呼び出している。

このため、新しくシェルスクリプトを作ったり、パッケージをインストールした場合、実際はパスの通ったディレクトリに実行可能ファイルがあるにもかかわらず、そのコマンドがハッシュテーブルに登録されていないため、コマンドを見付けることができない場合がある。このようなときは rehash でハッシュテーブルの再構築をすることで、シェルに新しいコマンドを認識させることができる。
% cd /home/user
% echo $path
/home/user/bin
% cat > bin/sample (bin/sample にシェルスクリプトを作る)
#!/bin/csh -f
echo test
[Ctrl-D]
% chmod +x bin/sample (実行可能属性をつける)
% sample
sample: command not found.(/home/usr/bin にはパスが通っているのに sample を見付けられない)
% rehash (ハッシュテーブルを再構築)
% sample (実行できる)
test
また、
% /home/user/bin/sample
% ./bin/sample
などと絶対パスで指定すれば、ハッシュテーブルは参照されない。

csh・tcsh で、上記のハッシュテーブルを使用しないようにするには unhash コマンドを使う。

PATH そのものの説明については PATH を参照のこと。

bashの場合
bash のハッシュテーブルは、csh・tcsh と考え方が微妙に異なる。hash コマンドを参照のこと。

rename ファイル名の一括変更 (リネーム・一括置換)

ファイル名の変更は、伝統的な UNIX においては mv コマンドを使用するが、複数ファイルを一括してリネームすることはできない。一括変更したい場合は for・sed・mv などを組み合わせて行う。

一方、Linux においては rename コマンドを使ってファイル名の一括変更が可能である。rename コマンドは util-linux-ng パッケージに含まれており、おそらくは Linux の全ディストリビューションにて利用可能と思われる。

実行例
% rename .htm .html *.htm
→ 拡張子を .htm から .html に変更
% rename foo- bar- foo-*.txt
→ foo-*.txt を bar-*.txt に変更
% rename hoge "" hoge*.txt
→ ファイル名先頭の hoge を削除
% rename "" hoge *.txt
→ ファイル名の先頭に hoge を加える

rename コマンドは、実際の処理としては、
1. コマンドラインで指定されたファイル名を、元ファイル名とする。
2. ファイル名に FROM が含まれていたら TO に置換し、新ファイル名とする。
3. rename(2) にて、元ファイル名 → 新ファイル名 にリネームする。
を行うシンプルなつくりだが、シンプルすぎていろいろと注意が必要である。

まず、置換の際に単純に文字列として置換するのみであることに注意。対象文字列がファイル名なのかディレクトリ名なのかに関わらず、単純に置換する。
% rename abc def abc/file.c
とすると、abc/file.c → def/file.c となる。def/ というディレクトリがあればファイル移動になるが、def/ が存在しない場合はエラーとなる。

また、置換対象文字列が複数含まれていても、最初の文字列のみ置換される。
% rename abc def abc/abc.c
とすると、abc/abc.c → def/abc.c となる。

単純な文字列置換なので、
% rename / - dir/*.txt
とすることで、
dirA/file1.txt → dirA-file1.txt
dirA/file2.txt → dirA-file2.txt
dirB/file3.txt → dirB-file3.txt
などと、ディレクトリ構成をフラットにすることもできる。

クセのあるコマンドにも関わらず、rename コマンドには実行前にどのように置換されるかを表示するようなオプションは存在しない。拡張子変更などに留めておいた方がよいかもしれない。

もうひとつの rename コマンド
ネット上の情報によると、世の中には以下のように正規表現にて置換文字を指定できる rename コマンドもあるようだ。
% rename 's/.htm/.html/' *.htm
% rename 's/foo-/bar-/' foo-*.txt
% rename 's/^hoge//' hoge*.txt
% rename 's/^/hoge/' *.txt

DOS・Windows の rename コマンド
DOS における rename コマンド (ren コマンド) は
rename *.txt *.csv
という置換ができるが、Linux の rename コマンドではこの書き方はできない。
>> OSオンラインマニュアル(man) Linux rename(2)
>> OSオンラインマニュアル(man) Linux rename(1)

renice 現在実行中のプロセスのプライオリティ (優先順位) を変更する

デフォルトでは、プロセスはプライオリティ 0 で実行されているが、このプライオリティを変更する。なお、一般ユーザは優先順位を下げることしかできない。優先順位を上げることができるのは root のみである。
% xeyes &
[1] 1562
⇒ xeyes をバックグラウンドで実行。プロセス ID は 1562
% renice 4 1562
1562: old priority 0, new priority 4
⇒ プロセス 1562 のプライオリティを 4に変更)
% renice 0 1562
renice: 1562: setpriority: Permission denied
⇒ プロセス 1562 のプライオリティを 0 に戻そうとしても、一般ユーザは優先順位を上げることはできない

-u ユーザ名
指定したユーザが実行したプロセスのプライオリティを全て変更する。
% renice 20 -u user1

renice はすでに実行を開始しているプロセスのプライオリティを変更するコマンドである。起動時からプライオリティを変更するには nice を使うとよい。
>> OSオンラインマニュアル(man) FreeBSD renice(8)
>> OSオンラインマニュアル(man) Linux renice(8)

rlogin リモートログイン。

-l ユーザ名 ローカルホストとリモートホストでユーザ名が違う場合指定する。

リモートホストの ~/.rhosts に、ローカルホスト名とローカルホストでのユーザ名が記述されていれば、パスワード入力なしでログインできる。そうでなければ、パスワード入力が必要になる。

ログイン時の login: や password: のプロンプト部分では、Ctrl-d を押すことで rlogin を終了できる。パスワードを忘れてどうしてもログインできなくなったら login: と表示された後に(何も入力せず) Ctrl-d を押せばよい。

また、ログイン後は、~ (チルダ) の後に Ctrl-y で rlogin を suspend できるが、現在行を入力途中だとうまくいかない。シェル上で Ctrl-c を押し、新しいプロンプトを表示してから ~ を押して Ctrl-y を押せばよい。なお、このように suspend した rlogin は fg で再開できる。
>> OSオンラインマニュアル(man) Linux rlogin(1)
>> OSオンラインマニュアル(man) FreeBSD rlogin(1)
>> OSオンラインマニュアル(man) Solaris10 rlogin(1)

rm ファイル・ディレクトリを削除する

UNIX/Linux の rm コマンドは、ファイルやディレクトリを削除するコマンドである。rm コマンドは古くから存在するため (最初の UNIX である V1 で登場)、あらゆる UNIX/Linux 系 OS で使用可能である。


rm コマンドの基本的な使い方
% rm file
とすることで、file を消すことができる。
% rm file1 file2 file3 ...
だと、複数のファイルを削除する。もちろん
% rm *.txt
とファイルグロブ・ワイルドカードを使うこともできる。

ディレクトリを一括削除するには rm -r とする。
% rm -r dir/
パーミッションによる警告を抑止し、エラーメッセージも抑止して、消せるものはとにかく消す場合は rm -rf とする。
% rm -rf dir/

ディレクトリの削除
ディレクトリを rm コマンドで削除しようとすると、
% rm mydir
rm: mydir: is a directory
または
rm: cannot remove `mydir': ディレクトリです
などとエラーになる。

一般的には、ディレクトリの削除には rm コマンドではなく rmdir コマンドを使う。
% rmdir mydir
また、BSD 系の rm コマンドには -d オプションがあり、
% rm -d mydir
とすることでディレクトリを削除できる。ただし、rmdir コマンドも、rm -d も、ディレクトリが空でないと削除できない。

あるディレクトリ以下にファイルがあろうがなかろうがディレクトリごと全てを削除したい場合は
% rm -r mydir
とする。

なお、Linux で使用されている coreutils の rm について、JM ページのマニュアルでは
-d または --directory
ディレクトリが空で無くても、ディレクトリをunlinkする。 (スーパーユーザのみ使用可能)
とあるが、少なくとも 2005年には -d オプションは無視するようになっており、2010年頃に -d オプション自体が削除された模様である。

シンボリックリンクの削除と落とし穴【2017-10-25追記】
rm コマンドでシンボリックリンクを削除することができる。
% ln -s file mysymlink
% rm mysymlink
あくまで削除するのはシンボリックリンクであって、そのリンク先のファイル・ディレクトリには何も影響はない。

★以下 2017-10-25 追記。
ディレクトリを指しているシンボリックリンクがあるとして、シンボリックリンクだけを消すつもりで
% rm mysymlink
とすべきところを、誤って
% rm -rf mysymlink/
とすると、シンボリックリンクは消えず、リンク先のディレクトリが全部消えてしまう。「余計なスラッシュを付けない」「不用意に -rf オプションを付けない」というのが教訓であるが、unlink コマンドを使うという手もある。

unlink コマンドは、引数はひとつだけで、ファイル・シンボリックリンクの削除はできるが、ディレクトリの削除や、再帰的な削除はできない。内部的にはシステムコール unlink(2) を呼んでいるだけなので、unlink(2) でエラーになるものは全部削除できない (なお、ディレクトリを削除するシステムコールは rmdir(2) である)。

単一ファイルの削除の場合、rm コマンドではなく unlink コマンドを使うクセをつけておくとよいかもしれない。

ハードリンクしたファイルの削除
ハードリンクしたファイルを削除した場合どうなるかを下記に示す。
% touch sample.txt
→ sample.txt を作成し、
% ln sample.txt sample2.txt
→ ハードリンクで sample2.txt を作成
% ls -l
-rw-r--r-- 2 68user realuser 40 5 31 15:50 sample.txt
-rw-r--r-- 2 68user realuser 40 5 31 15:50 sample2.txt
→ sample.txt と sample2.txt は全く同じもの。第2カラムのリンク数が "2" となっている。
% rm sample2.txt
→ sample2.txt を削除すると
% ls -l
-rw-r--r-- 1 68user realuser 40 5 31 15:50 sample.txt
→ リンク数が 1つ減って 1 になる

rm コマンドのオプション一覧
-i 1つ1つのファイルについて本当に削除するか確認を求める
rm コマンドに -i オプションを付けると、
% rm -i file.txt
remove file.txt?

% rm -i file.txt
rm: remove 通常ファイル `file.txt'?
といったふうに、削除してよいかを確認してくる。y を入力すると削除するが、y 以外だと削除しない。

必要なファイルを消してしまわないかどうか不安な人は
% alias rm "rm -i' (csh・tcsh の場合)
% alias rm="rm -i" (sh・bash の場合)
と alias を設定しておくのも手だが、慣れてくるうちに
% \rm file.txt
などと alias を無効化してしまうのがクセになってしまい、肝心なときにも役に立たないというのは非常にありがちな話である。
-r 再帰的に指定ディレクトリ以下を削除する
-f パーミッションに関係なく全て削除する。
例えばパーミッションの「w」を落としたファイルを消そうとすると、
% chmod 444 file
% rm file
override r--r--r-- user/group for file?
のように、本当に消していいのか聞いてくる (y を押すと消去。それ以外のキーを押すと消さない)。-f オプションを付けると、このようなときにユーザに問い合わせることなく消去してしまう。もちろん他人のファイルなど、パーミッション的に削除できないものは -f オプションを付けても消すことはできない。

誤削除を防ぐために
rm コマンドで * や ? などのメタキャラクタを使う場合は、まず echo コマンドや ls コマンドで確認する癖を付けるとよい。
% rm *.txt
の前に
% echo *.txt
または
% ls *.txt
として、本当に消してもよいか確認しよう。例えば
% rm * .txt (誤って * と .txt の間に空白を入れてしまった)
とする前に
% ls * .txt
として確認すれば、
ls: .txt: No such file or directory
となって、誤りに気づくだろう。また、tcsh を使っているなら、シェル変数 rmstar を利用するのもよい。

ファイルを消せるかどうか
rm コマンドでファイルが削除できるかどうかは、本質的にはそのファイルが置かれているディレクトリにパーミッション「w」(書き込み) が立っているかどうか、で決まる。-f オプションの項で説明した
override r--r--r-- user/group for file?
というメッセージは、rm コマンドが確認のために聞いているだけである。詳しくは chmod コマンドのエントリを参照してほしい。

文字化けしたファイルの削除 【2017-07-04 追加】
文字化けしたファイルを削除したい場合、下記のように ? や * などのワイルドカードを使うとよい。
% ls -l
-rw-r--r-- 1 user group 0 Jul 4 13:43 abc???????
% rm abc*
すべて文字化けしている場合や、? や * ではうまく絞り込めない場合、
% ls -li
22327771 -rw-r--r-- 1 user group 0 Jul 4 13:43 ???????????????
として inode を確認した上で、下記のようにすれば削除したり、リネームしたりすることができる。
% find . -inum 22327771 -exec rm {} \;
→ 削除
% find . -inum 22327771 -delete
→ rm を使わず、delete オプションを使ってもよい。
find の -inum にて、削除ではなくリネームする例も記載しているので参考にしてほしい。

関連コマンド
BSD 系 UNIX で、どうしても消せないファイルがある場合は、ls -lo でファイルを見て、ファイルフラグが立っていないかどうか調べるとよい。ファイルフラグは chflags コマンドで設定できる。
>> OSオンラインマニュアル(man) Linux rm(1)
>> OSオンラインマニュアル(man) Solaris10 rm(1)
>> OSオンラインマニュアル(man) FreeBSD rm(1)

rmdir ディレクトリの削除

削除するディレクトリの中にファイルやサブディレクトリがあってはいけない。
あるディレクトリ中にファイルしかない場合は、
% rm -r directory

% rm directory/*
% rmdir directory
は同じ。
>> OSオンラインマニュアル(man) Linux rmdir(2)
>> OSオンラインマニュアル(man) Linux rmdir(1)
>> OSオンラインマニュアル(man) FreeBSD rmdir(1)
>> OSオンラインマニュアル(man) Solaris10 rmdir(1)

rmuser システムからユーザを削除する。FreeBSD のみ。

/etc/passwd・/etc/group から該当ユーザの削除、crontab データの削除などを行う。

アカウント hoge を削除する場合は、
# rmuser hoge
とする。これにより hoge のホームディレクトリも消去される。ただしこの他にもユーザ固有のファイルが残っている可能性はある。例えば Canna を使っているなら、/usr/local/lib/canna/dic/user/ に各ユーザの辞書ファイルが残っている。このような個別のアプリケーションが管理するファイルは削除されない。

FreeBSD でのアカウント削除は rmuser だが、Linux・Solaris・NetBSD では userdel コマンドを使う。
>> OSオンラインマニュアル(man) FreeBSD rmuser(8)

route ルーティング情報の設定・表示

引数の書き方が FreeBSD・Linux・Solaris で少しずつ異なる困ったコマンドである。

FreeBSD 編
% route add default 192.168.0.1
⇒ デフォルトルートとして 192.168.0.1 を設定
>> OSオンラインマニュアル(man) FreeBSD route(8)
>> OSオンラインマニュアル(man) Linux route(8)

rsh リモートシェル

別のホスト (リモートホスト) で任意のコマンドを実行する。

リモートホスト foo.bar.com に user というアカウントがある場合は、
% rsh -l user foo.bar.com command
とする。ローカルホストでのユーザ名と、リモートホストでのユーザ名が同じな場合は
% rsh foo.bar.com command
と、-l オプションを省略できる。

% rsh foo.bar.com ls > output.txt
とすると、foo.bar.com で ls コマンドを実行した結果を、ローカルホストの output.txt に出力する。一方、
% rsh foo.bar.com "ls > output.txt"
とクォーティングすると、foo.bar.com で ls コマンドを実行した結果を、foo.bar.com の ~/output.txt に出力する。

rcp・rsh を使うには、リモートホストの ~/.rhosts に、ローカルホスト名とローカルホストでのユーザ名が記述されている必要がある。

rcp・rsh はセキュリティに少々問題がある。詳しくは ~/.rhosts で説明する。
>> OSオンラインマニュアル(man) Solaris10 rsh(1M)
>> OSオンラインマニュアル(man) Solaris10 rsh(1)
>> OSオンラインマニュアル(man) FreeBSD rsh(1)
>> OSオンラインマニュアル(man) Linux rsh(1)

rsync ファイル・ディレクトリのバックアップ・ミラーリング・同期

rsync コマンドは、ファイル・ディレクトリのバックアップやミラーリング・同期処理を行うコマンドである。リモートサーバへの同期も可能である。また、差分のあるファイルのみを高速にミラーリングすることができる。

ミラーリングやバックアップを行うだけなら cp コマンドでも実現可能だが、rsync コマンドには以下のようなメリットがある。
  • ミラーリングが可能 (単純な cp だと、削除されたファイルがコピー先に残ってしまう)
  • リモートマシンへ/リモートマシンからのバックアップが可能
  • 2回目以降の実行では、前回実行時との差分を調べ、必要なファイルのみ転送するため高速である

基本
もっとも基本的な使い方は、
% rsync -av /foo/from_dir /bar/to_dir
である。これはローカルマシン内の /foo/from_dir 以下を /bar/to_dir/ にコピーを行うもので、物理的な別ディスクにバックアップしたり、USB メモリなどに保存したりする場合に有用だろう。もし /bar/to_dir が存在していなくても、自動的に作成される。

なお、上記の結果、
/bar/to_dir/from_dir/...
というファイルが作成される。そうではなく from_dir 直下のファイルが to_dir 直下に作成してほしい場合は以下のように転送元ディレクトリの末尾にスラッシュを付ける (from_dir ではなく from_dir/ とする、ということ)。
% rsync -av /foo/from_dir/ /bar/to_dir

オプション -av の意味を説明する。-a を指定することで、rsync はアーカイブモードで動作するようになる。アーカイブモードとは頻繁に使用されるオプション群に名前を付けたもので、実際は -a は -rlptgoD と同じである。各オプションの意味は以下のとおり。
  • ディレクトリを再帰的にコピーする (-r)
  • シンボリックリンクを、そのままシンボリックリンクとしてコピーする (-l)
  • パーミッションをそのままコピーする (-p)
  • タイムスタンプをそのままコピーする (-t)
  • グループをそのままコピーする (-g)
  • ファイルオーナー (所有者) をそのままコピーする (-o)
  • デバイスファイルやを特殊ファイルを、そのままコピーする (-D)
-v は、コピーしたファイル名や、コピーしたバイト数などの転送情報を表示するオプションなので、慣れないうちは -v を指定した方が理解が早いだろう。

実行例
rsync を実行すると、以下のようにファイルコピーするファイル・ディレクトリを表示し、最後に転送量や転送速度などを表示する。
% rsync -av /foo/from_dir /bar/to_dir
building file list ... done

created directory to_dir
./
file.txt
program.c
(略)
sent 125706799 bytes received 117812 bytes 14802895.41 bytes/sec
total size is 125368532 speedup is 1.00

一度目の転送が完了したら、もう一度同じコマンドを実行してみよう。
% rsync -av /foo/from_dir /bar/to_dir
building file list ... done

sent 80627 bytes received 20 bytes 53764.67 bytes/sec
total size is 125368532 speedup is 1554.53
今度はあまり時間がかからずに終了したはずだ。rsync が from_dir と to_dir の差異をチェックし、転送すべきファイルは存在しないと判断したため、ファイルのコピーが行われなかったからである。

もし何かしらエラーが発生した場合は、最後のレポート部分に、さらに以下のようなエラー情報が表示される。
rsync error: some files could not be transferred (code 23) at main.c(977) [sender=2.6.9]

リモートへのコピー
rcp や scp などと同様に、転送先のディレクトリ指定にホスト名やユーザ名を付加すればよい。
% rsync -av /foo/from_dir/ example.com:to_dir/
→ example.com の to_dir/ に転送する。ユーザ名は、ローカルのユーザ名と同じものを使用する
% rsync -av /foo/from_dir/ user@example.com:to_dir/
→ example.com の to_dir/ にユーザ名 user で転送する。
% rsync -av -e ssh /foo/from_dir/ user@example.com:to_dir/
→ rsh でなく、ssh でログインする

上記の例はいずれも転送先がリモートホストの場合だったが、転送元がリモートホストでも問題ない。
% rsync -av -e ssh user@example.com:from_dir/ /foo/to_dir/
→ リモートからローカルへ転送する

オプションは以下のとおり。
表示系オプション
-v または --verbose … コピーしたファイル名や、コピーしたバイト数などの転送情報を表示する。
-v オプションは複数個指定でき、-v より -vv の方が、さらに -vv より -vvv の方がより詳細な情報を表示する。
-q または --quiet … 転送情報を表示しない。
--stats : 転送後に、より詳細なファイル数・転送サイズを表示する。
Number of files: 5528
Number of files transferred: 15
Total file size: 125368532 bytes
Total transferred file size: 174602 bytes
Literal data: 0 bytes
Matched data: 0 bytes
File list size: 80611
File list generation time: 0.325 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 81077
Total bytes received: 800
-h または --human-readable … バイト数などを読みやすい形で表示する。
通常の -v オプションでは、以下のような形のメッセージになる。
sent 125531503 bytes received 117812 bytes 7179960.86 bytes/sec
total size is 125368532 speedup is 1.00
これに -h オプションを付けると、キロバイト・メガバイト単位で表示するので少しだけ読みやすくなる。
sent 125.53M bytes received 117.81K bytes 4.12M bytes/sec
total size is 125.37M speedup is 1.00

情報保存系オプション
-a または --archive … アーカイブモード。-rlptgoD を指定したのと同じ (-H が含まれていないことに注意)
-H または --hard-links … ハードリンクをそのまま反映する。
-p または --perms … パーミッションをそのままコピーする。
-E または --executability …
--flags … ファイルフラグをそのままコピーする。
-l または --links … シンボリックリンクを、そのままシンボリックリンクとしてコピーする。
-t または --times … タイムスタンプをそのままコピーする。
--devices … ブロックデバイスをコピーする (root のみ有効)
--specials … 名前付きパイプや FIFO などの特殊ファイルをコピーする
-D … "--devices --specials" と同じ
-o または --owner … ファイル所有者をそのままコピーする (root で実行した場合のみ有効)
-g または --group … グループをそのままコピーする

-z または --compress … データ転送時に圧縮を行う
--compress-level=NUM … 圧縮レベルを指定する

各種オプション
-c または --checksum
転送要否を決定する際、タイムスタンプとファイルサイズではなく、128bit の MD4 チェックサムを用いて同一ファイルか否かをチェックする。
-r または --recursive
ディレクトリを再帰的にコピーする。
-R または --relative
送信元のディレクトリ部分を、相対パスとして転送先に送信する。
% rsync -av /foo/bar/baz.c remote:/tmp/
→ 転送先には /tmp/baz.c として保存される。
% rsync -avR /foo/bar/baz.c remote:/tmp/
→ 転送先には /tmp/foo/bar/baz.c として保存される。
-u または --update
転送先に既にファイルが存在し、転送先のタイムスタンプの方が新しい場合は転送しない
-S または --sparse
穴あきファイルを効率よく転送する
-n または --dry-run
コピーや転送を実際には行わず、行われる転送内容の出力のみ行う
--list-only
コピーや転送は行わず、転送対象となるファイルの表示のみ行う
-W または --whole-file
rsync アルゴリズムを使用せず、ファイル全体を転送する
--existing または --ignore-non-existing
転送先に存在しないファイルは転送対象外とする (新規ファイルの作成を行わない)
--ignore-existing
転送先に存在しているファイルは、転送対象外とする (新規ファイルの作成のみ行う)
--remove-source-files
転送に成功したファイルは転送元から削除する (ただしディレクトリは残す)
--delete
delete extraneous files from destination dirs
--max-size=SIZE
転送対象とするファイルサイズ上限を指定する
--min-size=SIZE
転送対象とするファイルサイズ下限を指定する。SIZE の例を以下に示す。
--max-size=2K (=2*1024)
--max-size=2M (=2*1024*1024)
--max-size=2G (=2*1024*1024*1024)
-f, --filter=RULE
add a file-filtering RULE
--exclude=PATTERN
指定したパターンにマッチするファイルを転送対象外とする。
例: --exclude="*.txt"
→ 拡張子 txt のファイルは転送対象外とする
--bwlimit=KBPS
帯域制御を行い、指定の速度以下で転送を行う (KBPS は KByte/秒 で指定)

rtprio リアルタイムスケジューリングを使用する

詳細は idprio を参照のこと。
>> OSオンラインマニュアル(man) FreeBSD rtprio(1)

rup リモートマシンの状態を表示する

リモートマシンがブートしてからの時間やロードアベレージを表示する。
% rup foo.example.com
⇒ foo.example.com 指定のホストの情報を表示する

ホスト名を指定しない場合は、ローカルネットワーク内の全ホストの情報を表示する。rup は RPC を使ってリモートホストからのデータを取得するため、相手側の RPC が無効になっていたり、ファイアウォールで RPC のパケットがさえぎられたりしていると情報を取得することはできない。
>> OSオンラインマニュアル(man) Linux rup(1)
>> OSオンラインマニュアル(man) FreeBSD rup(1)

sa 実行されたコマンドの統計を表示

実行例。
% sa
 1153854 1090871940.28re     6312.96cp        5avio     6640k   
     547    93155.10re     2519.26cp      142avio       28k   XF86_SVGA
    1072   100625.12re      988.70cp      674avio      335k   netscape
     800    53517.01re      662.73cp      714avio      288k   navigator-4.6.bi
   26798    93573.57re      600.53cp       18avio     1109k   perl5.00404
    2581     6879.25re      493.89cp       33avio       47k   mpg123
    3766    71222.94re      149.59cp      117avio     1301k   mule-19.28
     558    93430.00re      144.95cp        1avio       17k   asclock
      58      181.45re      117.25cp      294avio       13k   lame
    1158      641.07re       89.20cp       10avio      810k   a.out
     498    94084.53re       85.24cp        2avio       24k   moused*
(以下略)
それぞれ、
  • 実行回数
  • 実行時間 (分単位)
  • ユーザ時間とシステム時間を合計 (分単位)
  • 1回実行したときの I/O 操作の平均回数
  • CPU 時間 1 秒あたりのメモリ使用量 (KB 単位)
  • コマンド名
を表す。例えば mule-19.28 は
  • 3766 回実行され、
  • 1187時間2分(71222.94) 実行され、
  • そのうちユーザ時間とシステム時間は2時間29分(149.59)、他の 1185 時間はユーザの入力待ちだったということ
  • 1回実行したとき、平均 117 回 I/O 操作をし、
  • CPU 時間 1 秒あたりのメモリ使用量が 117KB、
ということである。

sa を実行するには、あらかじめ accton でログを取って、/var/account/acct を作成しておく必要がある。
>> OSオンラインマニュアル(man) FreeBSD sa(8)

script コンソールへの出力をファイルに書き出す。

% script
と実行してから
% exit
とするまでのキータイプ、出力の全てをファイル (デフォルトでは typescript というファイル) に保存する。
% script outfile

% exit
と出力ファイル名を指定することもできる。
>> OSオンラインマニュアル(man) Linux script(1)
>> OSオンラインマニュアル(man) Solaris10 script(1)
>> OSオンラインマニュアル(man) FreeBSD script(1)

sed 文字列の置換・削除などの編集を行う

UNIX/Linux の sed コマンドは、ストリームエディタと呼ばれるもので、ファイルや標準入力から受け取った文字列に対して、置換・削除等の編集を行うことができる。1979年にリリースされた Version 7 UNIX にて登場した古いコマンドであるため、FreeBSD・Linux・Solaris 等、様々な UNIX 系 OS で使用可能である。

目次:
sed コマンドの基本的な使い方
文字列 aaa を 文字列 bbb に置換するには 's///g' を使う。
% sed 's/abc/def/g' < file > file2
⇒ file 中の文字列 abc を def に変換して file2 に出力する
標準入力に対して使うこともできる。
% command | sed 's/abc/def/g'
⇒ command の出力結果から文字列 abc を def に変換して出力する

aaa の部分には正規表現を使うことができる。
% ls | sed 's/[a-z]/X/g'
⇒ ls の出力の中の小文字のアルファベットを X に変換する。
正規表現部分がシェルに解釈されないように、常に s/// を シングルクォート('') で囲むようにしよう。マッチした部分を再利用したい場合、"\(" 〜 "\)" で囲んだ部分を "\1" で参照することができる。
% ls | sed 's/\(file*\)/cp \1 \1.bak/'
cp file1.txt file1.txt.bak
cp file2.c file2.c.bak
ファイルを上書き更新したい場合は、-i オプションを使う。このとき、バックアップファイルの拡張子を指定する。
% sed -i.bak -e 's/abc/def/' *.txt
→ バックアップファイルとして *.txt.bak が作成される
バックアップ不要である場合は、実装によりやり方が異なる。
% sed -i -e 's/abc/def/' *.txt
→ GNU sed の場合
% sed -i '' -e 's/abc/def/' *.txt
→ BSD・macOS sed の場合

sed の実体
sed はなかなかに複雑かつ高度なコマンドで、実はチューリング完全な言語である。sed の実体は、どの行を対象とするかを表す「アドレス」と、どう編集するかを表す「コマンド」をペアで指定する、というものである。このペアを「スクリプト」と言う。

下記の例をご覧いただくと、アドレスとコマンドの関係性がわかるだろう。

「アドレス: 3行目」を対象に、「コマンド: 行を削除する」場合:
% sed '3d' < file.txt
→ 3行目が削除され、それ以外の行はそのまま出力。アドレスは 3 であり、コマンドは d である。
「アドレス: 3行目」を対象に、「コマンド: 文字列を置換する」場合:
% sed '3s/abc/def/g' < file.txt
→ 3行目のみ abc を def に置換。それ以外の行はそのまま出力。アドレスは 3 であり、コマンドは s/abc/def/g である。
「アドレス: 正規表現 ^d にマッチする行」を対象に、「コマンド: 文字列を置換する」場合:
% ls -l | sed '/^d/s/abc/def/g'
→ 行頭が d である行のみ abc を def に置換。それ以外の行はそのまま出力。アドレスは /^d/ であり、コマンドは s/abc/def/g である。

「アドレス」は省略可能である。その場合、全ての行を対象に「コマンド」が実行される。よく使用する "sed s/aaa/bbb/g" という形は、「アドレス」を省略しているわけである。一方、「コマンド」を省略することはできない。アドレスだけを記載すると、下記のようにエラーとなる。
% sed '10'
sed: -e expression #1, char 2: missing command
→ Linux で確認
sed '10'
sed: 1: "10": command expected
→ FreeBSD で確認

スクリプト (アドレスとコマンドのペア) を複数記述したい場合は、下記のように -e オプションを複数指定する。
% sed -e 's/aaa/AAA/g' -e 's/bbb/BBB/g' file.txt
下記のように sed コマンドを複数パイプでつなげてもよいが、CPU やメモリが若干無駄になることと、-e オプションを複数つらねたのとでは処理結果が異なることを理解した上で使ってほしい。
% sed 's/aaa/AAA/g' < file.txt | sed 's/bbb/BBB/g'

スクリプト (アドレスとコマンドのペア) がない場合、つまり
% command | sed
は何も処理を行わず、command の出力をそのまま表示する。これはつまり sed コマンドのデフォルト挙動は処理結果を出力する、ということを意味する。

sed のアドレス
数字
該当する行を対象とする。
% command | sed '2d'
→ 2行目を削除
数字N,数字M
N行目からM行目を対象とする。
% command | sed '3,5d'
→ 3〜5行目を削除
数字N~数字M
N行目からM行おきの行を対象とする (GNU sed のみ)。
% command | sed '1~2d'
→ 1行目から2行おきの行を削除する (つまり偶数行が表示される)
/正規表現/
正規表現にマッチする行を対象とする。
% command | sed '/[0-9][0-9]/s/abc/def/g'
→ 数字2桁を含む行について、abc を def に置換
\[文字]正規表現[文字]
正規表現にスラッシュを含む場合 /\/usr\/local\/ などとエスケープすればよいが、見づらくなってしまうのを避けたい場合は、\@/usr/local@ などと別の文字を使うことができる。
\X〜X、\_〜_、\!〜! など、どんな文字で挟んでもよい。
% command | sed '\@/usr/local@s/abc/def/g'
→ 数字2桁を含む行について、abc を def に置換

なお、アドレスの最後に "!" を付けると、否定の意味になる。
% command | sed '3!d'
→ 3行目「以外」を削除 (つまり 3行目のみ表示)
% command | sed '3-5!d'
→ 3〜5行目「以外」を削除 (つまり 3〜5行目のみ表示)
% command | sed '/[0-9][0-9]/!s/abc/def/g'
→ 数字2桁を「含まない」行について、abc を def に置換

sed のコマンド
s コマンド
正規表現で置換処理を行う。書式は "s/[置換前文字列]/[置換後文字列]/[フラグ]" である。

\(〜\) で囲んだ部分は、置換文字列内で \数字 として後方参照することができる。
% cat file | sed 's/\([ad]\).\([cf]\)/\1X\2/g'
aXcdXfaXc
012aXc345bcaXc

この例では、[ad] にマッチした部分を \1 で、[cf] にマッチした部分を \2 で参照している。つまり \(〜\) で囲んだ部分は \1、\2、\3、\4、\5 … で参照することができる。

主なフラグを下記に示す。
g: マッチした箇所が複数あった場合、全てを置換する。
g フラグなしの場合、s コマンドは各行に対して、最初に見付かった文字列しか変換を行わない。
% echo aabbccaabb | sed 's/aa/AA/'
AAbbccaabb
→ 最初の aa は AA に置換されるが、2番目以降の aa はそのまま
% echo aabbccaabb | sed 's/aa/AA/g'
AAbbccAAbb
→ 全ての aa が AA に置換される
d コマンド
該当行を削除する。
p コマンド
表示する。

その他
ちなみに perl の文字列置換機能である s/// は、sed が由来であることは言うまでもない。なお、sed より perl の正規表現に慣れている場合は、sed の代わりに
% perl -pe 's/a/b/g' < file
を使う手もある。

ある文字を改行コードに変換、あるいは改行コードをある文字に変換する場合は、sed ではなく tr か perl を使う方がよい。
>> OSオンラインマニュアル(man) Linux sed(1)
>> OSオンラインマニュアル(man) Solaris10 sed(1)
>> OSオンラインマニュアル(man) FreeBSD sed(1)

sendmail メール管理プログラム

最も有名な MTA (Mail Transfer Agent) で、メールの送信・中継・受信を管理する。普通はメーラー (RMAIL・Mew・netscape など) を使ってメールを送受信するので、直接 sendmail を実行する必要はないが、使い方を知っておいて損はないと思う。foo@example.com 宛にメールを送りたい場合、
% sendmail foo@example.com
From: my@mail.address (あなたのメールアドレス)
To: foo@example.com
Subject: This is test mail.
(ここに空行を入れる。ここまでがヘッダ。ここから先がボディ)
メールの内容
.(ドットのみの行を入力すると終了)
となる。ドットのみの行を入力すると終了してしまうので、本当に「.」のみの行を送りたいときは -i オプションを使うとよい。

宛先である foo@example.com を、sendmail の引数と、To: フィールドの両方に書いていることに注意してほしい。この場合、本当にメールが送信されるのは、引数で示した方のメールアドレスであり、To: foo@example.com は実際の宛先とは一切関係ない。すなわち
% sendmail foo@example.com
To: hogehoge@fugafuga (foo@example.comとは全く関係ないメールアドレス)
としてもよいし、From: フィールドも、送信者のメールアドレスを書く必要はない。
ただし、他のヘッダに誰が送ったか書き込まれるので、いたずらメールを送ろうなどと考えないこと。

-i 「.」のみの行を送っても、ボディの終了とみなさないようにする。
この場合、ファイルに送信したい内容を書いて
% sendmail foo@example.com < file
とするか、Ctrl-D で EOF を送るとよい。
-t To: Cc: Bcc: フィールドを認識する。
先に書いたように、sendmail はデフォルトでは To: Cc: Bcc: などのフィールドを無視し、コマンドラインで指定されたメールアドレスのみにメールを送信するが、-t オプションを付けると、To: Cc: Bcc: フィールドを解析し、各フィールドで指定されたメールアドレスにメールを送信する。-t オプションを付けた場合、コマンドラインで送信先メールアドレスを指定する必要はない。

また、mail.server.com で動いている SMTP サーバ経由でメールを送る場合は
% telnet mail.server.com smtp
HELO あなたのドメイン名
MAIL FROM: あなたのメールアドレス
RCPT TO: 送信先のメールアドレス
DATA (ここまでがエンベロープ。ここから先がヘッダ)
From: うそのメールアドレス
To: 送り先メールアドレス
Subject: タイトル
(空行。ここから先がボディ)
メールの内容
.(ドットのみの行はボディの終了を示す)
QUIT
とすればよい。なお、これは SMTP プロトコルの例であって、sendmail に限ったことではない。

なお、sendmail が /usr/lib にある UNIX もあるので注意。
>> OSオンラインマニュアル(man) FreeBSD sendmail(8)

seq 連番・数列を生成するコマンド

seq コマンドとは、連番・数列を生成し、出力するコマンドである。

引数ひとつパターン
引数にひとつの数字を指定した場合、1 からその数字までの連番を出力する。
% seq 5
1
2
3
4
5

引数ふたつパターン
引数にふたつの数字を指定した場合、初期値と最終値として出力する。
% seq 7 11
7
8
9
10
11

引数3つパターン
引数に3つの数字を指定した場合、開始値・増分・最終値とみなす。
% seq 5 2 11
5
7
9
11
→ 5から始め、2ずつ増加し、11になったら終了。

小数・減少・マイナス
開始値・増分・最終値いずれも、小数を指定することができる。
% seq 1.3 0.75 3.56
1.30
2.05
2.80
3.55

間隔にマイナス値を指定することで、減少させることができる。
% seq 3 -1 0
3
2
1
0

開始値や終了値にマイナス値を指定することもできる。
% seq -6 4 8
-6
-2
2
6

seq コマンドのオプション
-w オプションを指定すると、同じ文字数になるようゼロパディングがなされる。
% seq -w 1 100
001
002
(略)
099
100

-s オプションで区切り文字を変更できる。
% seq -s, 1 5
1,2,3,4,5
→ カンマ区切りに
% seq -s", " 1 5
1, 2, 3, 4, 5
→ 「カンマ+空白」区切りに

-f オプションで数値フォーマットを柔軟に設定することができる。printf(3) のような書き方ができるので、かなり強力。
% seq -f'%.2f' 9 12
9.00
10.00
11.00
12.00
→ 小数点以下2桁
% seq -f'%5.2f' 9 12
 9.00
10.00
11.00
12.00
→ 小数点以下2桁かつ全体を5桁右揃え
% seq -f'%07.2f' 9 12
0009.00
0010.00
0011.00
0012.00
→ 小数点以下2桁かつ全体を7桁ゼロパディング
% seq -f'%+.0f' -5 2 5
-5
-3
-1
+1
+3
→ 符号を必ずつける
% seq -f'"%05.2f"' -s", " 3 7
"03.00", "04.00", "05.00", "06.00", "07.00"
→ ダブルクォートで囲み、カンマ区切りとする
% seq -f'192.168.0.%.0f' 1 127
192.168.0.1
192.168.0.2
(略)
192.168.0.126
192.168.0.127
→ IPアドレスの連番を生成

-f オプションで頑張るとわかりづらくなるので、下記のようにループさせる方がよいかもしれない。
% for i in `seq 1 127`; do echo "192.168.0.$i"; done
192.168.0.1
192.168.0.2
(略)
192.168.0.126
192.168.0.127

seq コマンド は GNU の coreutils に含まれており、Linux 系 OS ではおおむね使うことができるだろう。

FreeBSD や macOS などの *BSD 系では seq コマンドの代わりに jot コマンドを使うのが一般的であるものの、FreeBSD 9.0 以降・NetBSD 3.0 以降で seq コマンドを使うことができる。

*BSD・macOS・SysetmV 系 OS に coreutils をインストールした場合、gseq などの名前でインストールされてしまうかもしれない。
>> OSオンラインマニュアル(man) FreeBSD seq(1)
>> OSオンラインマニュアル(man) Linux seq(1)

set シェル変数を設定する。csh・tcsh の内部コマンド。

シェル変数を設定する。
% set sample=test
⇒ シェル変数 $sample の値が test となる
シェル変数を参照するときは $sample と書けばよいが、代入時は $ を付けてはいけない。つまり
% set $sample=test
はシェル変数 sample の値を設定しているわけではない (実際には $sample の値が hoge にセットされていた場合は、hoge=test となる)。

csh・tcsh のシェル変数には配列をセットすることが可能である。配列として a b c をセットする場合は
% set array=(a b c)
% echo $array
a b c
とする。一方、文字列として「a b c」をセットする例は以下の通り。
% set str="a b c"
% echo $str
a b c

echo する分には違いがわからないが、変数の要素数を意味する「$#シェル変数」を参照すると、配列の要素数が 3 となっていることがわかる。
% echo $#array
3
% echo $#str
1

引数を省略すると、現在設定されているシェル変数を全て表示する。

setenv 環境変数を設定・定義・更新する。csh・tcsh の内部コマンド。

setenv コマンドは、環境変数を設定・定義・更新する csh・tcsh の内部コマンドである。PATH の設定・更新を行う際によく使用される。シェル変数の設定は setenv ではなく set を使う。
また、sh・bash の場合は setenv ではなく export コマンドを使う。

環境変数の設定方法は下記のとおり。
% echo $SAMPLE
SAMPLE: 変数を定義していません.
→ 最初は未設定状態。
% setenv SAMPLE test
→ 環境変数 SAMPLE の値は test となる。
% echo $SAMPLE
test
→ echo で確認できる
% printenv SAMPLE
test
→ printenv コマンドでも確認
% /usr/bin/printenv SAMPLE
test
→ 念には念を入れて外部コマンドの printenv コマンドでも確認
% env | grep SAMPLE
SAMPLE=test
→ env コマンドでも確認
環境変数を削除するには unsetenv コマンドを使う。
% unsetenv SAMPLE
→ 環境変数 SAMPLE を削除
% printenv SAMPLE
→ 何も表示されなくなった

環境変数 PATH の更新方法
環境変数 PATH の末尾に追加する場合、既存の PATH と新しいパスをコロンでつなげよう。変数名の後のコロンは変数 $PATH ではなく ${PATH} と書くようにしよう($変数 の後にコロンを置くと、修飾子として機能してしまうため)。
% setenv PATH "${PATH}:/usr/local/sbin"
→ PATH の末尾に /usr/local/sbin を追加
% setenv PATH "${PATH}:${HOME}/bin"
→ PATH の末尾に $HOME/bin を追加。ホームディレクトリは ~ ではなく $HOME を使うこと。

環境変数 PATH 自体の説明やリスクは下記を参照してほしい。

表示・削除等
setenv コマンドの引数を省略すると、現在設定されている環境変数を全て表示する。あるいは env コマンドや printenv コマンドを使ってもよい。

setenv は csh・tcsh の内部コマンドである。sh・bash で環境変数を設定するには export コマンドを使う。

sh シェル (Bシェル、ボーンシェル)

ユーザインタフェイスが弱いので、ログインシェルとしてはあまり使われないが、速度が速く書式が洗練されているので、シェルスクリプトとしてよく使われる。

sh に便利なユーザインタフェース機能を追加したものが bash である。ログインシェルには bash や tcsh などの高機能なシェルを使うべし。

なお、FreeBSD では本来の sh でなく、機能を拡張した ash が使われている(しかし普通は、この ash を sh と呼ぶ)。また、Linux では sh は存在せず、sh は bash へのハードリンクになっている。

なお、sh は Bourne (ボーン) 氏が作ったので、B シェルと呼ばれる。
>> OSオンラインマニュアル(man) Solaris10 sh(1)
>> OSオンラインマニュアル(man) FreeBSD sh(1)

showrgb X 上で使える色と、その名前の対応表を表示

色名と、その色の RGB を調べることができる。
% showrgb
255 0 0 red
0 255 0 green
0 0 255 blue
などと表示された場合、
% kterm -fg red -bg blue
とすると、背景が青、文字が赤になる。なお、これは
% kterm -fg rgb:ff/00/00 -bg rgb:00/00/ff
と同じである。

shutdown システムをシャットダウンする

UNIXはマシンの電源をいきなり切ると、ファイルシステムが壊れてしまう可能性がある。マシンの電源を切る際は、必ず shutdown コマンドを使うこと。

シャットダウンの前に、ログインしている全ユーザにログアウトするように通知される。
-h システムを停止する (そのあと電源を切ればよい)
-r システムをリブートする
-k ログインしているユーザをログアウトさせる。実際にはシャットダウンしない

% shutdown -h now
⇒ いますぐシステムを停止する
% shutdown -r +3
⇒ 3分後にシステムをリブートする

(少くとも FreeBSD では) shutdown コマンドを実行できるのは、root と、operator グループに属するユーザだけである。一般ユーザ権限で shutdown を実行したい場合は、/etc/group の
operator:*:5:root
のところを
operator:*:5:root,hogehoge
などと書き換える。この例では root と hogehoge のみが shutdown を実行できるようになる。
>> OSオンラインマニュアル(man) Linux shutdown(2)
>> OSオンラインマニュアル(man) Linux shutdown(8)
>> OSオンラインマニュアル(man) Solaris10 shutdown(1M)
>> OSオンラインマニュアル(man) FreeBSD shutdown(8)

sleep 指定秒数だけ動作を止める

sleep コマンドは、指定された秒数だけ、そのプロセスの動作を止めるコマンドである。
ずっと処理を実行し続けていると負荷がかかるため、適当な時間ウェイトを入れる場合に使う。たとえば巨大な tar ファイルを作成していて、毎秒の進行状況を知りたい場合は、sh・bash なら
% while true; do ls -l foo.tar ; sleep 1 ; done
csh・tcsh なら
% while (1)
while? ls -l foo.tar
while? sleep 1
while? end
などとする。

5分間 (300秒) 動作停止するには
% sleep 300
とする。sleep コマンドは、スクリプトの中で使うことが多い。
% ( echo username ; sleep 1 ; echo password ; sleep 1 ; echo ls ; sleep 1 ) | telnet foo.bar.com
なんてこともできたりする。

また、30秒単位で cron からプログラムを実行するには crontab に
* * * * * date & sleep 30 ; date
などと指定するとよい。

指定した時間にあるコマンドを実行したい場合は、普通 at や cron を使う。しかし、これまでコマンドライン上で動かしていたプログラムを いきなり cron 上で動かそうとしても、環境変数などの問題ですんなりと動くとは限らない。そういうときは
% sleep 36000 ; command
とすれば、きっちり 10時間後にコマンドが実行される。とにかく数時間後に一度だけ動けばよい、という場合はお勧め。ちなみにカップラーメンにお湯を入れた後に打つコマンドは
% sleep 180 ; printf "\a"
である。

小数指定
*BSD や、新しめの Linux のように、
% sleep 3.45
などと小数点以下の秒数まで sleep できる実装もあるが、POSIX 的には整数のみを受け付けるのが正しい。もしお使いの Linux で小数指定ができない場合、RedHat 系 Linux では usleep コマンドが用意されているようなので試してみてほしい。
また、Ubuntu では sleepenh コマンドで小数指定ができるらしい。

suffix 指定
Linux で使われている GNU の sleep コマンドでは、適切な suffix を指定することにより分・時間・日単位で sleep 秒数を指定できる。
% sleep 1s (1秒 sleep)
% sleep 2m (2分 sleep)
% sleep 3h (3時間 sleep)
% sleep 4d (4日 sleep)
% sleep 3h 20m (3時間と20分 sleep)
→ 複数組み合わせることもできる
% sleep 1 3 (1+3で、4秒 sleep)
→ こういうこともできるようだ

システムコール・ライブラリ関数は sleep(3)・usleep(3)・nanosleep(2) を参照のこと。
>> OSオンラインマニュアル(man) Linux sleep(1)
>> OSオンラインマニュアル(man) Linux sleep(3)
>> OSオンラインマニュアル(man) Solaris10 sleep(1)
>> OSオンラインマニュアル(man) FreeBSD sleep(1)

socat ソケットリレーツール (proxy)

ひとことで言うと proxy ツールである。入力と出力にファイル・標準入出力・コマンド・他のマシンなど、いろいろな種類を割り当てることができる。用途別に紹介しよう。

コマンドライン・ファイルから入力したデータを、他のマシンに送る
キーボードから入力
% socat STDIN TCP4:www.jp.freebsd.org:80
GET / HTTP/1.0(と入力して Enter)
(Enter)
.... (http://www.jp.FreeBSD.org/ の内容を取得できる) ...
より便利なキーボードからの入力
入力を READLINE として、さらにオプションでヒストリファイルを指定すると、Ctrl-n や Ctrl-p などで前回入力した内容を再利用できる。
% socat READLINE,history=$HOME/.http_history TCP4:www.jp.freebsd.org:80
telnet で web サーバとお話する際などは毎回同じような内容をタイプするのでうんざりするが、socat を使うと非常に便利である。

ファイルから入力
あらかじめ、
GET / HTTP/1.0(Enter)
(Enter)
という内容の http.dat を用意しておき、
% socat OPEN:http.dat TCP4:www.jp.freebsd.org:80
とすることで http.dat に結果が追記され、以下のような内容になる。
GET / HTTP/1.0

HTTP/1.1 200 OK
Date: Sun, 20 Feb 2005 05:43:01 GMT
Server: Apache
Content-Length: 199
(略)
socat はこのように、
% socat 入力 出力
とすると、「入力」の内容を「出力」に送り、「出力」が返した内容を「入力」に追記することに注意しよう。

プロトコルの内容を確認
「入力」に「TCP4-LISTEN:ポート番号」と指定すると、ローカルの指定されたポート番号を LISTEN する。「出力」は www.jp.FreeBSD.org:80 としているため、ブラウザで http://localhost:8080 にアクセスすれば、あたかも http://www.jp.FreeBSD.org/ を閲覧しているかのような状態になる。
% socat -v -d -d TCP4-LISTEN:8080,reuseaddr TCP4:www.jp.freebsd.org:80
2005/02/20 14:52:34 socat[8532] N listening on AF=2 0.0.0.0:8080
> GET / HTTP/1.1\r
> Host: localhost:8080\r
> \r
< HTTP/1.1 200 OK\r
< Date: Sun, 20 Feb 2005 05:55:41 GMT\r
< Server: Apache\r
< Last-Modified: Thu, 03 Feb 2005 14:35:13 GMT\r
< ETag: "26c078-39ec-46122a40"\r
< Content-Length: 14828\r
この例では -v で入出力の内容を表示させ、-d -d でエラー発生時にメッセージを表示させている。また、ポート 8080 の LISTEN 時に REUSEADDR を指定している。

簡易サーバ
以下のような標準入力を標準出力に返すプログラムを echod.pl として作成する。
#!/usr/bin/perl
$|=1;
while (<STDIN>){
printf "%d: %s", ++$count, $_;
}
そして
% socat TCP4-LISTEN:8000,reuseaddr,fork system:'./echod.pl',nofork
とすると、echo サーバとなる。telnet や socat などで localhost:8000 に接続できる。

sockstat ソケット情報を表示する (FreeBSD)

sockstat はソケットの情報を表示する FreeBSD のコマンドである。実行例は以下の通り。

% sockstat
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
www httpd 715 3 tcp4 *:80 *:*
www httpd 715 4 tcp46 *:443 *:*
hoge ssh-agent 563 3 stream /tmp/ssh-YuE97tIS/agent.562
hoge sshd 548 3 stream -> ??
hoge sshd 548 5 tcp4 192.168.1.12:22 192.168.1.11:1336
root sshd 543 5 tcp4 192.168.1.12:22 192.168.1.11:1336
root inetd 525 4 tcp4 *:23 *:*
root inetd 525 5 dgram -> /var/run/log
www httpd 509 3 tcp4 *:80 *:*
www httpd 509 4 tcp46 *:443 *:*
root ntpd 390 4 udp4 *:123 *:*
root ntpd 390 5 udp4 192.168.1.12:123 *:*
root ntpd 390 6 udp4 127.0.0.1:123 *:*

概念は netstat を参照。
>> OSオンラインマニュアル(man) FreeBSD sockstat(1)

sort 行単位でソート・並べ替えを行う

UNIX/Linux の sort コマンドは、ファイル内容や文字列をソートするコマンドである。何番目のカラムに従ってソートするか、文字列としてソートするか数値としてソートするか、昇順・降順か、などを指定できる。


sort コマンドの基本的な使い方
ファイルの内容をソートする。
% sort sample.txt
コマンドの実行結果をソートする。
% command | sort
複数ファイルを対象とすることもできる。
% sort *.log

sort コマンドの出力は、デフォルトでは ASCII コード順に並べる (のだが、最近はいろいろめんどくさい。後述)。
% sort sample.txt
1
11
2
22
:
=
A
AB
_
a
ab
bc
逆順にするには -r オプションを使う。
% sort -r sample.txt
bc
(略)
1

ASCII コード順ではなく、数値として解釈してほしい場合は -n オプションを使う。典型的には、ファイルサイズ・回数をカウントする際に -n オプションを使うことが多い。

下記は、/var/log の下からファイルサイズ昇順でソートし、サイズの大きいもの 10件をリストアップする例である。
% ls -l /var/log/ | sort -k5,5 -n | tail -10
-rw------- 1 root root 1024256 Oct 22 03:47 log1
-rw------- 1 root root 1418032 Oct 29 03:24 log4
-rw------- 1 root root 1616547 Oct 8 03:08 log3
-rw------- 1 root root 1935428 Oct 8 03:08 log9
-rw------- 1 root root 3254279 Oct 21 10:09 log5
-rw------- 1 root utmp 5665152 Nov 1 03:11 log2
-rw------- 1 root root 62963872 Nov 1 08:31 log6
-rw------- 1 root root 107586181 Oct 29 03:29 log7

上記でも示したように、特定カラムをキーとしてソートする場合、-k オプションを使用する。
% sort -k3,3
と同じ値を指定すると、3 カラム目のみの比較を行う。
% sort -k3,3 -k1,1
というふうに、-k オプションを複数並べることがで、3カラム目が同じであれば 1カラム目で比較することもできる。

もし、
% sort -k3
とすると、3カラム目の先頭から行末までを 1カラムとして扱いソートする。-n オプションとの相性が悪いので、基本的には
% sort -k3,4
とすれば、3カラム目でソートし、3カラム目が同じ場合は 4カラム目でソートする。

sort + uniq コマンド
sort コマンドは uniq コマンドと共に使うことでさらに威力を発揮する。下記は、Web サーバのログから特定の1時間分のアクセスを抽出し、その IP アドレスの件数をカウントしたものである。awk コマンドで第一カラムの IP アドレスのみ出力し、sort コマンドでソートして同じ IP アドレスが連続した行になるようにした上で uniq -c とすると出現回数を出力してくれるので、sort -n で出現回数を数字としてソートしている。この例では、特定 IP アドレスのみ件数がダントツで多いため、この IP アドレスから何らかのアタックがあったのでは、などが疑われる。
% grep '29/Oct/2017:03' /var/log/httpd/access_log | awk '{print $1}' | sort | uniq -c | sort -n | tail -5
454 111.111.111.111
467 111.111.111.112
611 111.111.111.113
621 111.111.111.114
27212 11.22.33.44

sort コマンドのオプション
-c すでにソートされているかを調べる
-f 大文字と小文字の区別をしない
-m 複数のファイルをソートするとき、すでにそれぞれソートされている場合に指定。
-mをつけなくてもソート結果は同じだが、高速になる
-r 逆順にソートする
-R または --random-sort
ランダムにソートする。ただし sort -R はハッシュでソートするため、同じ行があると固まって出力されてしまう。重複値が隣り合うと困る場合は、shuf コマンドを使うとよい。
% for i in 1 2 2 2 3 3 3 3 3 4 5 6 7 8 ; do echo $i ; done | sort -R
→ sort -R だと 2 や 3 が必ず隣り合って出力される
% for i in 1 2 2 2 3 3 3 3 3 4 5 6 7 8 ; do echo $i ; done | shuf
→ shuf コマンドだと大丈夫
-n 文字列ではなく、数字とみなしてソート
% sort sample (デフォルトでは文字列としてソート)
1
12
2
20
% sort -n sample (数字としてソート)
1
2
12
20
-u 同一内容の行は1度しか表示しない。
% cat sample | sort
abc
def
def
ghi
% cat sample | sort -u
abc
def (同じ行は一度しか表示しない)
ghi
-h K・M・G などの接尾辞を解釈した上でソートする。
一部 UNIX の ls・du・df コマンドなどは -h オプション (--human-readable オプション) が指定されるとキロ・メガ・ギガなどと表す接尾辞 K・M・G などと表示する。
sort コマンドにも -h オプションを指定可能で、10G は 10M の 1024倍であるなどと計算しながら並び替えをおこなってくれる。
% du -h -d 1 / | sort -hr
10G /usr
10G /
311M /var
65M /boot
6.3M /lib
2.1M /etc
908K /bin
3.0K /dev
512B /mnt
+数字 指定の数のフィールドに従ってソートする。
% ls -l
-rw-rw-r-- 1 user group 869083 Jan 23 22:09 RMAIL
-rw-rw-r-- 1 user group 1721780 Jan 24 05:20 ba2.tgz
drwxr-xr-x 2 user group 1024 Jan 23 21:01 bin
-rw-rw-r-- 1 user group 4540 Jan 26 17:34 english.dvi
⇒ ls のデフォルト動作は、ファイル名によってソートされる
% ls -l | sort +4
drwxr-xr-x 2 user group 1024 Jan 23 21:01 bin
-rw-rw-r-- 1 user group 4540 Jan 26 17:34 english.dvi
-rw-rw-r-- 1 user group 869083 Jan 23 22:09 RMAIL
-rw-rw-r-- 1 user group 1721780 Jan 24 05:20 ba2.tgz
⇒ 4番目のフィールド=ファイルサイズのフィールドに従ってソート
% ls -l | sort +6
-rw-rw-r-- 1 user group 1721780 Jan 24 05:20 ba2.tgz
-rw-rw-r-- 1 user group 4540 Jan 26 17:34 english.dvi
drwxr-xr-x 2 user group 1024 Jan 23 21:01 bin
-rw-rw-r-- 1 user group 869083 Jan 23 22:09 RMAIL
⇒ 6番目のフィールド=作成時刻のフィールドに従ってソート
0番目のフィールドは行頭を表すので、sort +0 と sort は同じである。
>> OSオンラインマニュアル(man) Solaris10 sort(1)
>> OSオンラインマニュアル(man) FreeBSD sort(1)
>> OSオンラインマニュアル(man) Linux sort(1)

source ファイルに書かれたコマンドを実行する。csh・tcsh・bash 内部コマンド

source hoge とするのは、ファイル hoge に書かれた文字列を一つずつ自分の手でタイプしたのと同じことである。

例えば、~/.cshrc を書き変えたあと、その設定を有効にするためには、ログインしなおさずに
% source ~/.cshrc
とすると便利。
% csh -f .cshrc
としてしまうと、新しいシェルが起動してしまう。

なお、bash の内部コマンドにも source コマンドが用意されている。
% source ~/.bash_profile
で、~/.bash_profile の内容が現在実行中の bash に反映される。ただし sh には source コマンドはない。
% . ~/.profile
のように `.' (ドット) という内部コマンドを使うこと。

sox サウンドファイルのコンバータ

ファイル形式変換や、エフェクト効果をかけることができる。AIFF・au・raw・wave 形式などに対応している。

AIFF 形式のファイル sample.aiff を wave 形式にコンバートする場合は、
% sox sample.aiff sample.wav
tosha などで吸い出したraw データを wave に変換する場合は、
% sox -s -c 2 -w -r 44100 out.raw out.wav
とする(raw データには周波数などを記録したヘッダがないので、各種のパラメータ、オプションで補完してやる必要がある)。なお、上記のオプションは長くて覚えにくいので
% sox -t cdr out.raw out.wav
という短縮形を使える。

sox はフォーマット変換以外にも各種エフェクトをかけることができる。
% sox -v 0.5 foo.wav bar.wav
⇒ foo.wav の音量を半分にして bar.wav に出力
% sox sample.aiff sample.wav echo 0.9 0.4
⇒ 0.9 秒後にオリジナルの 0.4 倍の音量でエコーをかける。
ただし、FreeBSD 3.3-RELEASE では成功したが、FreeBSD2.2.7-RELEASE では音量変換の -v オプションが効かないようだ。

splay MP3、waveの再生ツール

split ファイルを複数のファイルに分割する。結合は cat で行う。

-b num numバイトごとに分割
-l num num行ごとに分割

ファイル sample を 1400キロバイトごとに分割するには
% split -b 1400k sample
とする。分割されたファイルは xaa、xab、xac ... となる。結合するには
% cat xaa xab xac > sample
とすればよい(xaa xab xacの順番のとおりに結合される)。

% split -b 2m sample test.
⇒ sample を2メガバイトごとに分割。test.aa、test.ab、test.ac ... というファイルが作成される。
>> OSオンラインマニュアル(man) Linux split(1)
>> OSオンラインマニュアル(man) Solaris10 split(1)
>> OSオンラインマニュアル(man) FreeBSD split(1)

stars 星が流れるデモ

+、-で星の流れるスピードを変えられる。スペースキーで星が停止する。

startx X Window System を起動する

FreeBSD の場合、/usr/X11R6/bin/startx であるが、その中で xinit を呼び、さらに xinitが X(/usr/X11R6/bin/X) を呼ぶ。

ユーザのホームディレクトリに ~/.xinitrc が存在すれば、そのスクリプトが実行される。この中で kterm や twm・fvwm・afterstep などのウィンドウマネージャを実行するようにしておくとよい。


/usr/X11R6/bin/startx の最後の行の
xinit $clientargs -- $serverargs
を、
xinit $clientargs -- $serverargs 2> $HOME/.xinitrc-errors
と書き換えると、~/.xinitrc の中で起こったエラーが ~/.xinitrc-errors に格納されるので便利。

stat ファイルの詳細な情報を表示する (ファイルサイズ・パーミッション・タイムスタンプ等)

stat コマンドは、ファイル名、ファイルサイズ、ブロック数、ファイルタイプ (ファイル、ディレクトリ、named pipeなど)、パーミッション、UID、GID、i-node、リンク数、最終アクセス時刻、更新時刻などを表示するコマンドである。


stat コマンドの基本的な使い方
Linux での stat コマンドの実行例を以下に示す。引数にファイル名やディレクトリ名を指定すると、そのファイルの詳細情報を表示する。
% stat sample.txt
  File: `sample.txt'
  Size: 3               Blocks: 8          IO Block: 4096   regular file
Device: fc03h/64515d    Inode: 4200774     Links: 1
Access: (0644/-rw-r--r--)  Uid: (  600/  68user)   Gid: (  600/  68user)
Access: 2017-12-05 20:51:00.000000000 +0900
Modify: 2017-05-25 14:06:09.717293917 +0900
Change: 2017-05-25 14:40:35.339251735 +0900

上記サンプルは以下のような意味である。
File ファイル名
Size ファイルサイズ
Blocks ブロック数
IO Block ブロックサイズ
(項目名表記なし) ファイルの種類
Device [デバイス番号 16進数表記]h/[デバイス番号 10進数表記]d の形式。デバイス番号って何だ?
Inode iノード番号
Link リンク数。ln でハードリンクすると増えていく
Access パーミッション
Uid ユーザーID/ユーザ名
Gid グループID/グループ名
Access 最終アクセス時刻
Modify 最終更新時刻
Change 最終ステータス変更時刻

上記は通常ファイルに対して stat コマンドを実行した例であるが、ファイルの種類によっては、下記のように項目が増える場合がある。
シンボリックリンクに対して実行:
→ File: `/usr/tmp' -> `../var/tmp' となる。
/dev/null などのデバイスに対して実行:
→ Device type: 1,3 が増える。

下記のように、複数ファイルを指定することもできる。
% stat *.txt dir/*

stat コマンドのオプション
Linux で使用できる GNU coreutils に含まれる stat コマンドのオプションは以下のとおり。

-L または --dereference
シンボリックリンクをたどる。このオプションを付けない場合、シンボリックリンク自身の情報を表示する。
-f または --file-system
そのファイル自身ではなく、そのファイルが属するファイルシステムの情報を表示する。
% stat -f /home/68user/sample.txt
File: "/home/68user/sample.txt"
ID: 7a6477d135465b7c Namelen: 255 Type: ext2/ext3
Block size: 4096 Fundamental block size: 4096
Blocks: Total: 25190501 Free: 20263789 Available: 18982497
Inodes: Total: 6414336 Free: 6264736
この環境ではファイルシステムは / であるため、/ の情報を表示していることになる。上記サンプルは以下のような意味である。
ID ファイルシステム ID
Namelen ファイル名の最大長
Type ファイルシステムの種類
Block size このファイルシステムのブロックサイズ
Fundamental block size よくわからないが、ブロックサイズが可変であるファイルシステムにおける、最低限必要なブロックサイズのことであろうか?
Blocks: Total このファイルシステム全体のブロック数
Blocks: Free このファイルシステム全体の未使用ブロック数
Blocks: Available このファイルシステム全体の利用可能ブロック数 (Total - Free)
Inodes: Total このファイルシステム全体の inode 数
Inodes: Free このファイルシステム全体の未使用 inode 数
-c [フォーマット文字列] または --format=[フォーマット文字列]
デフォルトの代わりに指定フォーマットで出力する。

ファイルサイズのみ表示する例:
% stat -c "%s" sample.txt
3
パーミッション・ファイルサイズ・ファイル名を表示する例:
% stat -c "%A %s %n" sample.txt
-rw-r--r-- 3 sample.txt
任意の文字列も混ぜ込んで表示できる。
% stat -c "permission: %A size: %s filename: %n" sample.txt
permission: -rw-r--r-- size: 3 filename: sample.txt
-c オプションで使用可能なフォーマット文字列は後述する。なお、"%" そのものを表示したい場合は "%%" とする。
--printf=[フォーマット文字列]
-c オプションでは "\n" などの改行コードには対応していないが、
--printf オプションでは "\n" や "\t" などが使える。勝手に改行はしてくれないので、最後に "\n" を付けるとよい。
% stat --printf="permission: %A\nsize: %s\nfilename: %n\n" sample.txt
permission: -rw-r--r--
size: 3
filename: sample.txt
--printf オプションで使用可能なフォーマット文字列は後述する。
-t または --terse
シンプルな形式で情報を表示する
% stat -t sample.txt
sample.txt 3 8 81a4 600 600 fc03 3674740 1 0 0 1495695645 1495695645 1495695645 4096

-c オプションや --printf オプションで使用可能な書式
GNU coreutils 版 stat コマンドの-c オプションや --printf オプションで使用可能な書式と実行例は以下のとおり。

パーミッション 8進数表記:
% stat -c "%a" sample.txt
644
上記はパーミッションが rw-r--r-- の例だが、もし --------- の場合、%a の表示は 0 となってしまう。この場合は 000 と表示したいだろうから、%a ではなく %03a とするとよい。
% chmod 000 sample.txt
% stat -c "%03a" sample.txt
000
パーミッションの人間が読める形式での表記:
% stat -c "%A" sample.txt
-rw-r--r--
割り当てられたブロック数:
% stat -c "%b" sample.txt
8
各ブロックの大きさ (バイト単位):
% stat -c "%B" sample.txt
512
SELinux のセキュリティコンテキスト文字列:
% stat -c "%C" sample.txt
stat: failed to get security context of `sample.txt': 利用可能なデータがありません
→ 当ページ管理人の環境では SELinux を無効化してあったので、上記のような表示となってしまった。
デバイス番号の 10進数表記:
% stat -c "%d" sample.txt
64515
デバイス番号の 16進数表記:
% stat -c "%D" sample.txt
fc03
raw モードの 16進数表記:
% stat -c "%f" sample.txt
81a4
ファイルの種類:
% stat -c "%F" sample.txt
regular file
所有者のグループID:
% stat -c "%g" sample.txt
600
所有者のグループ名:
% stat -c "%G" sample.txt
68user
リンク数:
% stat -c "%h" sample.txt
1
iノード番号:
% stat -c "%i" sample.txt
4200774
ls -li で表示される iノード番号と同じである。
マウントポイント:
% stat -c "%m" sample.txt
?
ファイル名:
% stat -c "%n" sample.txt
sample.txt
クォートされたファイル名:
% stat -c "%N" sample.txt
`sample.txt'
最適な I/O 転送サイズのヒント情報:
% stat -c "%o" sample.txt
4096
よくわからないが、"block sizes, alignment and I/O hints" でググると何か書いてある気がする。
合計サイズ (バイト単位):
% stat -c "%s" sample.txt
3
通常ファイルの場合は、ファイルサイズ。ディレクトリの場合は消費ブロックサイズ、シンボリックリンクの場合は、シンボリックリンクのリンク先のファイル名のサイズ。
メジャーデバイス番号 (16進数表記):
% stat -c "%t" sample.txt
0
マイナーデバイス番号 (16進数表記):
% stat -c "%T" sample.txt
0
所有者のユーザID:
% stat -c "%u" sample.txt
600
所有者のユーザ名:
% stat -c "%U" sample.txt
68user
最初に作成した日時 (人間が読みやすい形式):
% stat -c "%w" sample.txt
?
マニュアルには "不明な場合には -" と書いてあったが、当ページ管理人の CentOS 環境では "?" が表示された。birthtime のことであろう。2017年5月現在の Linux では使えない。
最初に作成した日時 (Epoch からの秒数):
% stat -c "%W" sample.txt
?
マニュアルには "不明な場合には 0" と書いてあったが、当ページ管理人の CentOS 環境では "?" が表示された。birthtime のことであろう。2017年5月現在の Linux では使えない。
最終アクセス日時 (人間が読みやすい形式" sample.txt:
% stat -c "%x" sample.txt
2017-12-05 20:51:00.000000000 +0900
最終アクセス日時 (Epoch からの秒数):
% stat -c "%X" sample.txt
1512474660
1970年1月1日 00:00:00 からの経過秒数。
最終更新日時 (人間が読みやすい形式):
% stat -c "%y" sample.txt
2017-05-25 14:06:09.717293917 +0900
最終更新日時 (Epoch からの秒数):
% stat -c "%Y" sample.txt
1495688769
1970年1月1日 00:00:00 からの経過秒数。
最終変更日時 (人間が読みやすい形式):
% stat -c "%z" sample.txt
2017-05-25 14:40:35.339251735 +0900
最終変更日時 (Epoch からの秒数):
% stat -c "%Z" sample.txt
1495690835
1970年1月1日 00:00:00 からの経過秒数。

stat コマンドの存在意義
上記の一部は ls コマンドなどでも表示することができるものの、例えばシェルスクリプトからタイムスタンプを取得した場合、
% ls -l
drwxr-xr-x 3 root wheel 512 Sep 29 2008 olddir
dr-xr-xr-x 1 root wheel 0 May 25 14:55 newdir
のように、月が Jan・Feb などの英略語表記であったり、最終更新日時が 1年以内は月・日・時・分、それより古いものは年・月・日表記になるなど、扱いづらい場合が多い。

そのために、加工されていない情報を取得するために stat コマンドが作成されたものと思われる。

UNIX/Linux での stat コマンドの歴史
stat コマンドは、NetBSD 1.6 (2002年リリース) で初登場し、その後 FreeBSD・OpenBSD でも使えるようになった。Linux においては、GNU coreutils に含まれているため、RedHat Linux・CentOS・Ubuntu 等、すべての Linux にて statコマンドを使うことができる (おそらく sh-utils に 2002〜2005年に追加され、その後 coreutils に統合されたのではないか