知ってると便利な UNIX のコマンド

* UNIX の書籍などでよく目にする、 'rn(1)' や 'ctime(3)' の括弧の中に書く数字にはどういう意味があるの?

Cプログラム中で関数を使うときのような書き方ですが、これは、"UNIX manual" で、該当するドキュメントがある部分を 示すためにつけられた数字です。実際に 第3章にある "ctime" について の説明を読みたいときは、"man 3 ctime (Solarisでは、man -s 3 ctime)" と、man コマンドを実行することでドキュメントが参照できます。

伝統的なマニュアルは、このようなセクションに分かれています。

セクション 一般的なUNIX Solaris
1 ユーザコマンド 1B - SunOS/BSD互換コマンド
1C - 通信コマンド
1F - FMLIコマンド
1S - SunOSコマンド
1M - システム管理コマンド
2 システムコール システムコール
3 ライブラリ関数 3B - SunOS/BSD互換ライブラリ関数
3C - Cライブラリ関数
3E - ELF(Extensible Linking Formats)ライブラリ関数
3G - Cライブラリ関数
3I - ワイド文字関数
3K - カーネルVMライブラリ関数
3M - 数学関数
3N - ネットワーク関数
3R - RPCサービス関数
3S - 標準入出力関数
3T - スレッドライブラリ関数
3X - その他のライブラリ関数
4 ファイル形式
デバイスとデバイスドライバ
4B - SunOS/BSD互換ファイル形式
5 ファイルのフォーマット ヘッダ、テーブル、マクロ
6 ゲーム ゲーム
7 特殊ファイル 特殊ファイル
8 システムのメンテナンスや
オペレーション用のコマンド
 
9   9E - DDI/DKIエントリポイント
9F - DDI/DKIカーネル関数
9S - DDI/DKIデータ構造

man コマンドで、必ずセクションを指定する必要はありません。時間を計測する 'time' コマンドについて説明した "time(1)" と、 現在の時刻を求める 'time' 関数に関する "time(3)" が、別々の ページに書かれていることがあるような場合、関数の説明が見たいのに "man time" と指定すると、時間を計測する 'time' コマンドの説明が表示されます。このときに"man 3 time" と入力すれば、見たい方の 'time' 関数に関するマニュアルを選ぶことができます。

さらに、man コマンドにはキーワードで関連のあるマニュアルのリストを表示してくれる機能があります。

    man -k keyword

この際に windex エラーが出て一覧が表示されない場合、catman -w を実行してください。これにより、インデックスが作成されます。

man コマンドで表示されるマニュアルの内容をみると、タイトルが記述されています。このタイトルは以下のような意味があります。

NAME コマンドおよび関数の名前とその使用目的
SYNOPSIS コマンドの入力形式。コマンドラインにタイプするオプションやファイル名、また関数の引き数についてなどが記述されています。
DESCRIPTION コマンドおよび関数の動作やオプションの意味が詳細に記述されています。
FILES コマンドが実行されるにあたって、参照したり利用されたりするファイル名が記述されている。
SEE ALSO このコマンドに関連する他のコマンドや関連のある関数が記述されています。
BUGS コマンドや関数の使用制限などが記述されています。

* "-"で始まる名前のファイルは、どうやったら消せるの?

一番簡単な方法は、

    rm ./-filename 

とパスを指定することです ("-filename" はカレントディレクトリにあると仮定しています)。"-" をオプションだと解釈されるのを避けるこの方法は、他のコマンドに対しても使えます。多くのコマンド、特に getopt(3) という引数処理ルーチンを使って書かれているコマンドは、"これは最後のオプションで、これより後ろは全部オプションではありません" ということを示す "--" という引数 を受け付けます。すべての UNIX の rm コマンドが、"rm -- -filename" を使えるわけではありません。

rm コマンドの中には、 "-" を同じ目的で扱うものがあります。"rm - -filename" というのも試してみて下さい。

* コントロールコードなど、変な文字を含む名前のファイルはどうやったら消せるの?

手っ取り早い方法としては、

    rm -i *

と "-i" オプションを利用することです。これはカレントディレクトリの各ファイルに対し、消すかどうか尋ねてきます。望むファイルに対しては "y" と答え、それ以外には "n" と答 えて下さい。シェルによっては、ファイル名の8ビット目が立っている場合、Shell が 8ビット目を落としてしまいうまくいかないかもしれません。

もう一つの方法としては、"ls -i ." を使って問題としているファイルの i-node を求め、

    find . -inum 12345 -ok rm '{}' \; 

とすることです。"-ok" オプションは安全のためのチェックです。このオプションによって、rm コマンドを実行して良いかどうか確認を求めてくるようになります。 もし、すぐにでも消して良いと思ったり、ファイル名に変な文字列が入っていて、 表示すると画面がグチャグチャになるなら、確認を避けるために代わりに "-exec" を使うことができます。

ファイル名の中に '/' が入っている時はどうすれば良いの?

ううむ、理論的には '/' と '\0' の2文字だけはファイル名には現れることはありません。なぜなら、'/' はディレクトリやファイル名を区切るのに使われ、'\0' はファ イル名の終りを表すからです。

しかし、NFS を利用して Macintosh などの UNIX でないマシンのユーザーが、ファイル名に日付の入ったファイルを作ろうとする時に起こります。この場合、まず最初にやってみることは、このような操作をした Macintosh からその ファイルを何かスラッシュを含まない名前に変えてみることです。

それがうまく行かないか不可能な場合、スーパーユーザーでの操作が必要になります。 そして以下の手順を踏む必要があります。

  1. '/' の付いた名前のファイル名があるディレクトリと同じ親ディレクトリに、新しいディレクトリを作ります。

  2. 可能な限り全て (つまり '/' の付いた名前のファイル以外全部) を新しいディレクトリに移動します。

  3. '/' の付いた名前のファイルを含むディレクトリで、i-node を知るため "ls -id" を行ないます。

  4. ファイルシステムを umount します。

  5. '/' の付いた名前のファイルのあるディレクトリで "clri" を実行します。

  6. ファイルシステムに "fsck" を実行します。

  7. ファイルシステムをマウントし直します。

  8. あなたが作ったディレクトリを、古いディレクトリの名前に変えます。 (古いディレクトリは "fsck" によって無くなっているはず...)

  9. "lost+found" の中から新しいディレクトリに、きちんとした名前で移して完了です。

* C シェルから、標準出力と標準エラー出力を別々にリダイレクトするにはどうすれば良いの?

C シェルでは、">" を使用することで標準出力をリダイレクトできます。標準出力と標準エラー出力は ">&" を使用することで一緒にリダイレクトできます。しかし、標準エラー出力だけを直接リダイレクトする方法はありません。最も良い方法は、

    ( command > stdout_file ) >& stderr_file

というようにサブシェルで "command" を実行することです。標準出力はサブシェルの中で stdout_file にリダイレクトされ、標準出力が取り除かれた標準エラー出力が stderr_file にリダイレクトされます。

標準出力へリダイレクトするのを避けるだけなら、sh を使用する方法があります。

    sh -c 'command 2> stderr_file'
リダイレクト方法一覧 sh系
(sh,bash,ksh,etc)
csh系
(csh,tcsh,etc)
標準出力のリダイレクト > file
> file
>! file (noclobber変数を無視して出力)
標準出力の追加リダイレクト >> file
>> file
>>! file (noclobber変数を無視して出力)
標準エラー出力のリダイレクト 2> file ( command > /dev/null ) >& file
標準出力と標準エラー出力のリダイレクト > file 2>&1 >& file
標準出力と標準エラー出力をパイプを通して
コマンドに渡す
2>&1 | command |& command

*sudoでオーナーを変更したけどリダイレクト先のファイルの権限も変更したい時はどうすれば良いの?

sudoコマンドでオーナーを変更してコマンドを実行したけど、その結果をリダイレクトしたファイルには権限が反映されない。そんな時どう対処すれば良いか?それはシェルを利用して sudoを実行します。

    sudo sh -c "command > file"

* $PATH に '.' を入れると、どんな不都合が起こるの?

PATH のどこかに "." を入れると便利です。カレントディレクトリのプログラムを実行する時、"./a.out" の代わりに "a.out" と入力することができるからです。 しかしそこには落し穴があります。

"." が PATH の最初にある場合どうなるでしょう?カレントディレクトリは "/tmp" のようにだれでも書き込めるところだとします。そのディレクトリーに、たまたま誰かが残した "/tmp/ls" と言う名前のプログラムがあった場合、 (普通の "/bin/ls" コマンドを実行するつもりで) "ls" と入力すると 、シェルは他のユーザーが作ったプログラムの "./ls" を 代わりに実行させるでしょう。言うまでもなく、このような見知らぬプログラムを実行してしまい驚くことでしょう。

"." が PATH の最後にある場合は最初にある場合よりはましです。

    setenv PATH /usr/ucb:/bin:/usr/bin:.

同じように /tmp で "ls" と入力すると、シェルは "ls" という名前のプログラムを探しますが、"." の中を探そうとする前に /usr/ucb, /bin, /usr/bin を見るでしょう。このおかげで、誰か他のユーザーの作った "ls" というプログラムを不注意に実行する危険は少なくなります。しかし、これでも 100% 安全な訳ではありません。タイプミスで "ls -l" の代りに "sl -l" と打ち込んだとしたら "./sl" を実行するという危険があります。 "./sl" というプログラムが存在すればの話ですが...もし、"./sl"が悪意のあるコマンドであった場合、取り返しのつかないことになるかも知れません。多くの熟練した UNIX ユーザは、PATH に "." を入れずに作業します。

    setenv PATH /usr/ucb:/bin:/usr/bin

こうすると、カレントディレクトリでプログラムを走らせるために "program" の代わりに "./program" と打ち込む必要があります。しかし安全性の向上は 恐らく手間をかけただけの価値があるでしょう。

* システム中の全ての core ファイルや a.out ファイルを消したいのですがどうすればよいの?

findコマンドに -exec オプションを指定することで実現できます。

    find / \( -name a.out -o -name core \) -exec rm {} \;

* ファイルの階層構造をコピーするにはどうすればよいの?

cp -r では、パーミッションやシンボリックリンクがうまく繁栄できません。そこで、tar コマンドを利用します。

    cd fromdir; tar cpf - . | (cd todir; tar xpf -)

* "passwd","ftp","telnet","tip" 等の対話形プログラムをシェルスクリプトやバックグラウンドで実行するにはどうすればよいの?

これらのプログラムは端末からの入力を要求します。このようなプログラムはシェルスクリプトを使って自動化することはできません。

そこで、'expect' というプログラムが、このようなプログラムを自動で実行するためのインターフェースを提供してくれます。以下は expect コマンドを使ってパスワードを入力する例です。

#! /usr/local/bin/expect -f
# 最初の引数がユーザー名、2番めがパスワード 
  
set password [index $argv 2] 
spawn passwd [index $argv 1] 
expect "*password:" 
send "$password\r" 
expect "*password:" 
send "$password\r" 
expect eof

詳しくは、 http://expect.nist.gov/を参照してください。

* シングルユーザーモードでブートするにはどうすればいいの?

UNIX や UNIX-like の OS は数種類あります。シングルユーザーモードでブートする方法は、それぞれ異なった方方がとられています。代表的なものについて記述します。

Linux の場合:

LILO の Boot: プロンプトで、

    LILO: linux single 

とsingleをつけて起動することで run level 1 (single user mode) で起動します。しかし、シングルユーザーモードで起動しても rootのパスワードがわからないと ログインできないようになっています。そこで、以下のように /sbin/init を起動させずに shell を起動させることで root のパスワードを入力せずに single user mode にすることが出来ます。

    LILO: linux single init=/bin/sh 

また、ファイルシステムは、Read-Only なので

    mount -n -o remount,rw / 

として書き込み可能にすることが出来ます。

FreeBSD の場合:

Boot: プロンプトで、

    Boot: kernel -s

と -s をつけて起動することでシングルユーザーモードで起動します。
ルートパーティションを書き込み可能にマウントし直す方法は

    mount -u / 
Solaris の場合:

Boot: プロンプトで、

    Boot: boot -sw

と -sw をつけて起動することでシングルユーザーモードで起動します。w は書き込み可能でブートすることを意味します。

Mac OS X の場合:

起動音がしたらすぐに Command + S を押す。ルートパーティションを書き込み可能にマウントし直す方法は

    mount -uw /

* ps(Process Status)コマンド

現在動作中のプロセスを表示するコマンドです。

このコマンドを利用して、プロセス数や各プロセスごとのCPU使用率、各プロセスの優先度、プロセスIDなどを調べることができます。各プロセスのメモリー使用量は%MEM、SIZE、RSSに表示されます。SIZEはプログラム全体のサイズ、RSSが実際のメモリー使用量、%MEMはそれを割合で記述したもになります。CPU使用率は%CPU、優先度はNIに表示されます。

linux での表示例: System V 系の UNIX の場合 ps のコマンドラインオプションが違います。

  shin% ps aux
  USER       PID %CPU %MEM  SIZE   RSS TTY STAT START   TIME COMMAND
  bin        140  0.0  0.6   848   184  ?  S  May  5   0:00 /usr/sbin/rpc.portmap
  shin      3836  0.0  2.1  1236   752  p3 S   15:26   0:00 -bash
  shin      3899  0.0  1.2   884   368  p3 R   15:38   0:00 ps aux
  root         1  0.0  0.7   848   224  ?  S  May  5   0:21 init [3]
  root         2  0.0  0.0     0     0  ?  SW May  5   0:00 (kflushd)
  root         3  0.0  0.0     0     0  ?  SW May  5   0:02 (kswapd)
  ...
 
  shin% ps alx
   FLAGS   UID   PID  PPID PRI  NI   SIZE   RSS WCHAN       STA TTY TIME COMMAND
     100     0     1     0   0   0    848   224 wake_up     S   ?   0:21 init [3]
      40     0     2     1   0   0      0     0 remove_vfsm SW  ?   0:00 (kflushd)
      40     0     3     1 -12 -12      0     0 swap_tick   SW  ?   0:02 (kswapd)
     140     0    13     1   0   0    824   124 sigsuspend  S   ?   0:56 /sbin/update
     140     0    14     1   0   0    840   212 msgctl      S   ?   0:00 /sbin/kerneld
  100140     0   137     1   0   0   1104   452 syslog      S   ?   0:00 /usr/sbin/klogd
  ...
【System V 系の場合】
  UID      コマンドを実行したユーザーのユーザー名
  PID      プロセス ID
  PPID     親プロセスの ID
  C        プロセッサの使用状況
  STIME    プロセスが実行を開始した時間
  TTY      プロセスを制御する端末
  TIME     プロセスが使用した CPU時間の総計
  COMD     プロセスを起動するために使われたコマンド
 
【BSD 系の場合】
  USER     プロセスのユーザー名
  PID      プロセス ID
  %CPU     プロセスの CPU 使用率
  %MEM     プロセスのメモリ使用率
  SZ       プロセスが使用している仮想メモリの量
  RSS      プロセスの常駐設定サイズ(プロセスが占有している物理的なメモリ量)
  TT       プロセスを制御している端末
  STAT     プロセスの状態を示すフィールド
  TIME     プロセスが使用した CPU時間
  COMMAND  コマンド名(および引数)
 
【STATフィールド(1文字目)】
  R        実行中または実行可能
  S        休止(20秒以上が休止)
  I        アイドル状態(20秒以下の休止)
  T        中断
  H        停止
  P        ページ待ち
  D        I/Oデバイス待ち
  Z        ゾンビプロセス
 
【STATフィールド(2文字目)】
  <Blank>  コア
  W        スワップアウト
  >        メモリ要求のソフトリミットを超えたプロセス
 
【STATフィールド(3文字目)】
  N        低い優先度で実行されている
  #        nice (0以上の数)
  <        高い優先度で実行されている

* vim コマンドの設定

漢字コードおよびファイルフォーマット

文字コードを変更してファイルを保存
:set fenc=utf-8
:w

改行コードを変更してファイルを保存
:set ff=unix
:w

エンコーディングを変更してファイルを開き直す
:e ++enc=utf-8

UNIX形式でファイルを開き直す
:e ++ff=unix

括弧の自動マッチングを無効にする
let loaded_matchparen=1