Linux実践講座

Linux実践講座

コンピュータを便利に使う tips などをメモ

rsync でバックアップ

読了までの目安時間:約 9分

rsync は,ファイルやディレクトリをバックアップ/同期するための人気のあるツールです。変更分を検出して差分のみを転送することで、ネットワーク経由でも効率的にバックアップ/同期が行える点や、sshなどのリモートシェル経由での利用が可能です。

 rsync [オプション] コピー元 コピー先

コピー元のディレクトリ名の扱い

rsync -av ~/hoge /mnt/backupdisk
 hogeディレクトリのなかみと、そのディレクトリ自体がコピーされる。
rsync -av ~/hoge/ /mnt/backupdisk
 hogeディレクトリの中身はコピーされるが、ディレクトリはこぴーされない。

リモートホストへのバックアップ/同期

$ rsync -av ~/hoge  backupuser@hogehoge.com:/backupdir/

●同期する

$ rsync -av --delete ~/hoge backupuser@hogehoge.com:/backupdir/

●WindowsからLinuxへrsyncすると日本語が化ける

$ rsync -avzu --iconv=CP932,UTF-8 src dest

rsync 以外の自動バックアップ スクリプト

バックアップスクリプト:参照元 自動バックアップ運用(tar+GnuPG+rsync/ftp)

[root@centos ~]# vi backup.sh ← バックアップスクリプト作成
#!/bin/bash

#
# ローカル内でバックアップ
#

LANG=C

#
# 設定開始
#

# バックアップ対象リスト名
# ※バックアップ対象をフルパスで記述したリスト
BACKUPLIST=/root/backuplist
[ ! -s $BACKUPLIST ] && echo "$BACKUPLIST is not found" && error_exit

# バックアップ対象外リスト名
# ※バックアップ対象外をフルパスで記述したリスト
BACKUPNOLIST=/root/backupnolist

# バックアップ先ディレクトリ名
BACKUPDIR=/backup
mkdir -p $BACKUPDIR

# バックアップ保存世代数
# ※当日分を含めた過去分バックアップを保存する世代数
# ※過去分バックアップを保存しない場合は1を指定する
BACKUPGEN=8

# 暗号化・復号化パスフレーズ
# ※指定がないときは暗号化しない
PASS=''

# バックアップログファイル名
BACKUPLOG=/var/log/backup.log

#
# 設定終了
#

# 異常終了処理関数定義
error_exit () {
    rm -f $TMPBACKUPNOLIST
    exit 1
}

# バックアップファイルをバックアップ対象外リストに追加
# ※バックアップ先ファイルをバックアップしないようにする
TMPBACKUPNOLIST=`mktemp`
[ -s $BACKUPNOLIST ] && cat $BACKUPNOLIST > $TMPBACKUPNOLIST
echo "$BACKUPDIR/*backup.tar.bz2" >> $TMPBACKUPNOLIST

# 前回バックアップをリネーム
cd $BACKUPDIR
OLDBACKUPFILE=`ls backup.tar.bz2* 2>/dev/null`
if [ -f $OLDBACKUPFILE ]; then
    TIMESTAMP=`ls --full-time $OLDBACKUPFILE|awk '{print $6}'|tr -d -`
    mv $BACKUPDIR/$OLDBACKUPFILE $BACKUPDIR/${TIMESTAMP}$OLDBACKUPFILE > /dev/null 2>&1
fi

# バックアップログファイル作成
rm -f $BACKUPLOG
touch $BACKUPLOG
chmod 400 $BACKUPLOG

# バックアップ実行
echo "`date` backup start" >> $BACKUPLOG
tar cjvfP $BACKUPDIR/backup.tar.bz2 -T $BACKUPLIST -X $TMPBACKUPNOLIST >> $BACKUPLOG 2>&1
code=$?
if [ $code -ne 0 ]; then
    cat $BACKUPLOG | mail -s "BACKUP NG CODE IS $code" root
    rm -f $BACKUPDIR/backup.tar.bz2
    error_exit
fi
echo "`date` backup end" >> $BACKUPLOG

# バックアップ暗号化(暗号化・復号化パスフレーズ指定時のみ)
if [ ! -z $PASS ]; then
    echo "`date` encrypt start" >> $BACKUPLOG
    mkdir -p $HOME/.gnupg
    echo $PASS|gpg --passphrase-fd 0 --batch -c $BACKUPDIR/backup.tar.bz2 > /dev/null 2>&1
	code=$?
	if [ $code -ne 0 ]; then
	    cat $BACKUPLOG | mail -s "BACKUP NG CODE IS $code" root
	    rm -f $BACKUPDIR/backup.tar.bz2*
	    error_exit
	fi
    rm -f $BACKUPDIR/backup.tar.bz2
    echo "`date` encrypt end" >> $BACKUPLOG
fi

# バックアップ保存世代を超えた古いバックアップを削除
if [ $(ls $BACKUPDIR/*backup.tar.bz2*|wc -l) -gt $BACKUPGEN ]; then
    OLDBACKUPCNT=`expr $(ls $BACKUPDIR/*backup.tar.bz2*|wc -l) - $BACKUPGEN`
    for file in `ls -t $BACKUPDIR/*backup.tar.bz2*|tail -n $OLDBACKUPCNT`
    do
        rm -f $file
    done
fi

# バックアップ対象外リスト削除
rm -f $TMPBACKUPNOLIST

[root@centos ~]# chmod 700 backup.sh ← バックアップスクリプトへ実行権限付加

バックアップ定期自動実行設定:※毎日5:00にバックアップを実行する

echo "0 5 * * * root /root/backup.sh" > /etc/cron.d/backup

参考URL

はじめてrsyncを使う方が知っておきたい6つのルール
rsync でディレクトリの同期(バックアップ)
rsyncを使った熟練者レベルのバックアップ
自動バックアップ運用(tar+GnuPG+rsync/ftp)
rsync 世代管理バックアップ

samba で Linux サーバを Windows のファイルサーバにする

読了までの目安時間:約 7分

samba のインストール

yum -y install samba

smb.conf の設定 CentOS

CentOS 6.0, Samba 3.5.4

User認証なし

# -- Netwrok Related Options

workgroup = WORKGROUP
server string = Hoge Samba %v
netbios name = Hoge
unix charset = UTF-8
dos charset = CP932
hosts allow = 127. 192.168.0. 192.168.1.

# -- Standalone Server Options

security = share
guest account = nobody
guest ok = yes
username map = /etc/samba/smbusers

# -- Printing Options

load printers = no
; cups options = raw
disable spoolss = yes
printing = bsd

[Share]
comment = Share Folder
path = /home/share
browseable = yes
writable = yes
create mask = 0777
directory mode = 0777

User認証あり

# -- Netwrok Related Options

workgroup = WORKGROUP
server string = Hoge Samba %v
netbios name = Hoge
unix charset = UTF-8
dos charset = CP932
hosts allow = 127. 192.168.0. 192.168.1.

# -- Standalone Server Options

username map = /etc/samba/smbusers

# -- Printing Options

load printers = no
; cups options = raw
disable spoolss = yes
printing = bsd

sambaをインストールする
yum install samba

firewallの設定
# system-config-firewall-tui
参照URL http://kajuhome.com/security_trouble.shtml

SELinux off
/etc/sysconfig/selinux
 SELINUX=disabled

# /etc/rc.d.init.d/smb start
# /etc/rc.d/init.d/nmb start

CAPコードでかかれた日本語ファイル名をutf-8で表示する

Windows は CP932 という Shift-JIS を拡張した文字コードを使用、Linuxの文字コードは UTF-8 が使われる事が多くなっています。
ファイル名の文字コードを変換する場合 convmv コマンドを使用します。
CP932 から UTF-8 に変換する

$ convmv -f cp932 -t utf-8 * --notest

カレントディレクトリ以下のファイル名をすべて EUC-JP から UTF-8 に変換する。

$ convmv -r -f euc-jp -t utf-8 *  --notest

古いサーバの samba の設定がCAPコードになっており、サーバ移行の時にUTF-8に変換する事になったので goole で検索したらぴったりのコードがありました。
参照URL:http://linuxexpert.ne.jp/modules/pukiwiki/67.html
保存ファイル名:samba-viewfilename.pl

CAPのファイル名をEUCで表示

#!/usr/bin/perl
require "jcode.pl";

if(!@ARGV){$d=".";}else{$d=$ARGV[0];}
&CodeConv($d);

sub CodeConv{
my ($dir) = @_;
my (@f,$fo,$co,$a);

   opendir(IN,$dir);
      @f=readdir IN;
   close IN;

   foreach (@f){
      if (/^[^\.]/){
         $fo = $_;
         s/\:([0-9a-f][0-9a-f])/sprintf "%c",hex($1)/geo;
         $co = &jcode'getcode(*_);
         if ($co eq "sjis"){
            $a = &jcode'sjis2euc(*_);
#            rename "$dir/$fo","$dir/$_";
#            print "Convert: $dir/$fo -> $dir/$_\n";
            print "$fo -> $_\n";
         }
#         if ( -d "$dir/$_" ){
#            &CodeConv("$dir/$_");
#         }
      }
   }
}

参考にしたURL

Samba 2 日本語版で作成したファイルの Samba 3 への移行方法

find コマンド

読了までの目安時間:約 109分

find コマンドは使い方を知れば知るほど便利なコマンドです。一般的には find /hogehoge -name "*hoge*.jpg" といった使い方をしますが、オプションを組み合わせると色々な事が出来てしまいます。便利な find コマンドの使い方を覚えましょう。
-name
オプションとオプションを -o でつなぐと OR 条件になります。

$ find /directory \( -name "*.jpg" -o -name "*.png" \)

-exec
条件に合致したファイルに対して -exec 移行に指定したコマンドを実効する。
/hoge/hoge ディレクトリ下にある *.jpg ファイルを削除する。

$ find /hoge/hoge -name "*.jpg" -exec rm -f {} \;

-path
指定したパターンマッチングな文字列を元にファイルまでのパスを検索します。
/home/hoge ディレクトリ下から hogeword という文字列が記述されたファイルを検索しマッチした行とファイル名を表示する。

find /home/hoge -type -f -path "*" -exec grep "hogeword" {} \; -print

-user、-group
/hoge/hoge ディレクトリ下で オーナーが nobody のファイル、ディレクトリをオーナー apacheに変更する。

find /hoge/hoge -user nobody -exec chown apache.apahce {} \;

-atime、-ctime、-mtime、分単位なら-amin、-cmin、-mmin
ファイルのタイムスタンプを元に検索。-atim は最後にアクセス、-ctime は最後にステータスが変更、 -mtime は最後に修正されたタイムスタンプを調べます。引数の数字に、‘+’や‘-’を付加することで、日数*24時間より古いファイル(+)、新しいファイル(-)を検索することができます。
3日以内に修正されたファイルを表示する。

find /hoge/hoge -type -f -mtime -4 -exec ls -l {} \;

find コマンド man より

名前
find - ディレクトリ階層をたどって、条件を満たすファイルを検索する
書式
find [-H] [-L] [-P] [-D debugopts] [-Olevel] [path...] [expression]
説明
このマニュアルページは GNU 版 find の使用法を説明している。 GNU 版 find は、指定されたファイル名 (訳注: 上記「書式」における path...、 普通はディレクトリを指定する) を始点とするディレクトリツリーを 一つづつ探索し、与えられた式 (expression) を、 優先規則に従いつつ (「演算子」セクションを参照)、左から右へ 評価することによって検索を行う。 結果が確定すると (たとえば、and 演算なら左辺が偽になった時点で、 or 演算なら左辺が真になった時点で)、 find は検査の対象を次のファイル名に移す。

もし find を使用しているのが、セキュリティの問題をおろそかにできない環境なら (たとえば、 find を使って探索しているディレクトリが、自分以外のユーザにも 書き込み可能な場合など)、findutils 関連文書の 「Security Considerations」の章をお読みになるとよいだろう。 Finding Files という文書で、findutils に同梱されているはずだ (訳注: info "Finding Files" や info find で読むことができる)。 その文書では、ほかの点についてもこのマニュアルページより はるかに詳しい説明や考察が行われているので、この文書以上に情報源として お役に立つかもしれない。
オプション
-H, -L, -P というオプションは、シンボリックリンクをどう処理するかを決める。 こうしたオプションに続くコマンドライン引き数は、探索場所となる ファイル名やディレクトリ名と見なされる。ただし、それは、`-' で始まる 引き数や、`(' とか `!' という引き数が、続いて現れるまでだ。 そうした引き数、及びそれに続くいかなる引き数も、何を捜すべきかを 記述した式であると解釈される。パスが一つも指定されていない場合は、 カレントディレクトリ以下が探索の対象になる。 式が一つも指定されていない場合は、 -print が式として使用される (もっとも、 -print の代わりに、 -print0 の使用を考えた方がよさそうだが)。

このマニュアルページで説明する「オプション」には、式の一部として 使われるものもある。そうしたオプションは、 find の動作を制御するものであり、指定する位置は最後のパス名の直後になる。 これに対して、 -H, -L, -P, -D, -O という五つの「本来」のオプションは、指定するなら、最初のパス名の前で 指定しなければならない。なお、ダッシュを二個重ねた -- を使用して、後に続く引き数がオプションではないことを明示することも 可能だ (それでも、探索の始点となるパス名のリストでワイルドカードを 使用するならば、始点のすべてが `./' か `/' で始まるように しておいた方が、たいてい無難である)。

-P
シンボリックリンクをまったくたどらない。これがデフォルトの動作である。 find がファイルの情報を調べたり表示したりする際に、そのファイルが シンボリックリンクだったら、そのシンボリックリンクそのものの プロパティから取得した情報が使用されることになる。

-L
シンボリックリンクをたどる。 find がファイルの情報を調べたり表示したりする際に、 リンク先のファイルのプロパティから取得した情報が使用されることになり、 リンクそのものの情報は利用されない (ただし、 シンボリックリンクがリンク切れしていたり、 find がリンク先のファイルを調べることができなかった場合は除く)。 このオプションを使用すると、自動的に -noleaf が指定される。 後で -P オプションを指定し直しても、 -noleaf は依然として有効なままである。 -L が有効になっているとき、 find が探索中にサブディレクトリを指すシンボリックリンクに出会うと、 そのシンボリックリンクが参照しているサブディレクトリが探索される。
-L オプションが有効だと、述語 -type は (訳注: 「述語 (predicate)」とは、式を構成するオプション、判別式、 アクションなどの基本語彙を言う)、リンクそのものに対してではなく、 常にシンボリックリンクが指しているファイルのタイプに対してマッチを 行うようになる (シンボリックリンクがリンク切れしている場合を除く)。 -L を使用すると、述語 -lname や -ilname は常に偽を返す。

-H
コマンドライン上で指定された引き数を処理するとき以外、 シンボリックリンクをたどらない。すなわち、原則として、 find がファイルの情報を調べたり表示したりする際に、シンボリックリンク そのもののプロパティから取得した情報が、使用されることになる。 ただし、この動作には例外が一つあって、それは、コマンドラインで 指定されたファイルがシンボリックリンクであり、そのリンクが 解決できるときだ。その場合は、リンク先が何であれ、そこから 取得した情報が使用され (つまり、リンクがたどられるわけだ)、 シンボリックリンク自体の情報は、リンク先のファイルを調べることが できなかったときの、控えの情報として使われる。 -H が有効な場合に、コマンドラインで指定されたパスの中にディレクトリへの シンボリックリンクがあったら、そのディレクトリの中身が 調べられることになる (もっとも、-maxdepth 0 を指定すれば、 当然ながら、この動作は抑制されることになるだろうが)。

一つ以上の -H, -L, -P を指定した場合は、後のものが前のものを上書きする。 従って、コマンドラインで最後に指定されたものが、効果を持つわけだ。 -P はデフォルトなので、 -H や -L を指定しないかぎり、 -P オプションが有効になっていると考えるべきである。

GNU find は実際の探索に取りかかる前にコマンドラインの処理を行うが、 その際 stat システムコールを使ってファイルの情報を調べることが よくある。上述のオプションは、そのとき引き数がどう処理されるかにも 影響を与える。具体的に説明しよう。いくつのの判別式では、 コマンドラインで指定したファイルを目下検査の対象になっているファイルと 照合する。いづれの判別式でも、コマンドラインで指定したファイルは、 情報が調べられた後、そのプロパティのいくつかが保存されることになる。 名前を指定したファイルが実際にはシンボリックリンクであるとき、 -P オプションが有効な場合は (言い換えれば、 -H と -L のどちらのオプションも指定されていない場合は)、 照合に使用される情報は、シンボリックリンクのプロパティから 取得したものである。それ以外の場合、使用されるのはリンク先のファイルの プロパティから取得した情報だ。ただし、 find が (たとえば、権限が不十分だとか、リンク先のファイルが 存在しないとかの理由で) リンクをたどれない場合は、 リンクそのもののプロパティが使われることになる。

-H や -L オプションが有効な場合は、 -newer の引き数として指定されたのがシンボリックリンクなら、その参照がたどられて、 リンク先のファイルからタイムスタンプが取得されることになる。 同じことが、 -newerXY, -anewer, -cnewer についても言える。

式の一部として使用される -follow オプションには -L と同様の効果があるが、それが現れた位置から有効になるという点が 異なる (すなわち、 -L が使われずに、 -follow が使われた場合、 -follow より後で指定されたいかなるシンボリックリンクも参照がたどられるが、 その前に指定されたシンボリックリンクは参照がたどられない)。

-D debugoptions
診断用の情報を出力する。 find が期待どおりに動いてくれないとき、問題の原因追求に役立つことがある。 デバッグオプションを複数指定するときは、コンマで区切る。 findutils のバージョンの間で、デバッグオプションの互換性は保証されていない。 有効な全デバッグオプションのリストについては、 find -D help の出力を見るとよい。 有効なデバッグオプションの中には、以下のものがある。

help
デバッグ用オプションを説明する。
tree
式の構造 (expression tree) をオリジナルな形と最適化した形で示す。
stat
stat や lstat システムコールを使ってファイルが調べられたとき、 メッセージを表示する。 find プログラムは、そうしたシステムコールの回数を最少にしようとする。
opt
式の構造 (expression tree) の最適化に関する診断情報を表示する。 -O オプションを参照。
rates
各述語が何回成功し、何回失敗したかを示す情報を要約して表示する。

-Olevel
検査の最適化を有効にする。 find プログラムは、実行速度を上げるために判別式の順序を並べ替えるとき、 全体的な効果を維持しようとする。すなわち、付加的な作用のある 述語同士については、相互の相対的な順序を変更しないということだ。 各最適化レベルで行われる最適化は、以下のとおりである。

0
最適化レベル 1 と同じである。
1
これはデフォルトの最適化レベルであり、伝統的な動作に当たる。 式を並べ替えるとき、ファイル名にのみ基づいた判別式 (たとえば、 -name や -regex) が先に実行されるようにする。
2
判別式 -type や -xtype の実行は、ファイル名に基づいたいかなる判別式よりも後になるが、 inode から情報を取得する必要があるどんな判別式よりも先になる。 最近の Unix には readdir() 関数でファイルタイプを取得できるものが多い。 それ故、こうした述語は、まず stat 関数でファイル情報を取得する 必要がある述語よりも、評価に時間がかからないのである。
3
この最適化レベルでは、コストに基づいた検査の最適化を徹底して行う機能が 有効になる。判別式の順序が必要なら変更され、コストのかからない (すなわち、速い) 判別式が先に行われ、よりコストのかかる判別式が 後回しにされる。コストがほぼ同じ場合には、その述語が真を返しそうか、 偽を返しそうかによって、評価の順番が変わってくる。 or 演算では、真を返しそうな述語が先に評価され、 and 演算では、偽になりそうな述語が先に評価されるのである。

コストに基づいた最適化機能は、ある判別式が真を返す確率について 一定の考えを持っている。場合によっては、その確率について、 問題のテストの特性が考慮されることもある (たとえば、 -type f は、 -type c よりも、真になる可能性が高いと見なされる)。 コストに基づいた最適化機能は、現在のところその効果を評価中である。 もし、それによって find の性能が実際に向上することがなければ、捨てられることになるだろう。 反対に、信頼性があり、問題を起こしにくく、効果的であることが はっきりした最適化は、そのうち下位の最適化レベルでも採用される かもしれない。とは言え、リリース 4.3.x のシリーズでは、 デフォルトの動作 (すなわち、最適化レベル 1) を変更する予定はない。 なお、findutils のソースに付属するテスト集は、そのテストのすべてを 各最適化レベルの find で実行して、どの最適化レベルでも結果が同じになることを保証している。

式 (EXPRESSIONS)
式は、オプション、判別式、アクションから構成されている (訳注: オプション、判別式、アクションをまとめて、「述語 (predicate)」と呼ぶ)。 オプションは特定のファイルの処理よりもむしろ作業全体に影響し、 常に真を返す。判別式が返す値は、真のこともあれば、偽のこともある。 アクションには付加的な作用があり、真または偽を返す。 こうした式の要素は、みな演算子で区切られる。演算子が省略された場所には、 -and があるものと見なされる。

式の中に -prune 以外のアクションが存在しない場合は、 式の結果が真になったすべてのファイルに対して -print が実行される。
オプション

すべてのオプションは常に真を返す。 -daystart, -follow, -regextype を除いて、そのほかのオプションは、そのオプションより前に 指定された判別式も含め、すべての判別式に影響を及ぼす。 これは、オプションの処理は、コマンドラインが解析されるときに 行われるのに対して、判別式の方は、ファイルが調べられるまで 何もしないからである。 -daystart, -follow, -regextype の各オプションはこの点で異なっている。この三つのオプションは、 コマンドラインで自分より後に指定された判別式にしか影響を 及ぼさないのだ。従って、混乱を避けるためには、 -daystart, -follow, -regextype 以外のオプションは、 式の先頭部に置いた方がよい。そうしないと、警告が発せられる。

-d
-depth と同じ。FreeBSD, NetBSD, MacOS X, OpenBSD との互換性のためにある。

-daystart
-amin, -atime, -cmin, -ctime, -mmin, -mtime において、今日 (すなわち 0 日前) の始まりを今現在から 24 時間前ではなく、 コマンド実行当日の 0 時にする。 このオプションが影響を及ぼすのは、コマンドラインで自分より後に 指定された判別式だけである。

[訳注]:
-amin, -cmin, -mmin のことも考慮に入れると、次のように言えばよいのかもしれない。 デフォルトでは時間を計算するときの基準を 今現在に置くが、 -daystart を指定すると、時間計算の基準が今日の 24:00 になる。

-depth
ディレクトリそのものより先に、ディレクトリの中身を処理する。 アクション -delete を使用すると、 -depth オプションも自動的に設定される。

-follow
非推奨である。 -L オプションを代わりに使う方がよい。シンボリックリンクをたどる。 -noleaf が自動的に設定される。 -follow オプションが影響を及ぼすのは、コマンドラインで自分より後に指定された 判別式だけである。 -H や -L オプションが指定されていない場合、 -follow オプションの位置によって述語 -newer の動作が変わってくる。 -newer が -follow の後に来れば、 -newer の引き数として指定されたいかなるファイルも、それがシンボリックリンクなら、 リンクをたどられることになるわけだ。同じことが -newerXY, -anewer, -cnewer についても言える。 同様に、述語 -type も、シンボリックリンクそのものではなく、必ずシンボリックリンクが 参照しているファイルのタイプに対してマッチを行うようになる。 -follow を使用すると、述語 -lname と -ilname は常に偽を返す。

-help, --help
find のコマンドラインの使用法をざっと説明して終了する。

-ignore_readdir_race
通常、find は stat 関数でファイル情報を取得できなかったとき、 エラーメッセージを吐くことになっている。 ところが、このオプションを指定した場合は、find が ディレクトリからファイル名を読み込んでから、そのファイルに対して stat 関数を実行しようとするまでの間に、ファイルが消去されても、 エラーは表示されない。この動作は、コマンドラインで名前を指定した ファイルやディレクトリに対しても適用される。このオプションは コマンドラインを読み込む際に有効になるので、ファイルシステムの ある部分をこのオプションを有効にして探索し、別の部分はこのオプションを 無効にして探索するといったことはできない (そうしたことをやりたかったら、 find コマンドを二回実行する必要があるだろう。一回は、 このオプションを付けて、もう一回はこのオプションなしで)。

-maxdepth levels
コマンドライン引き数として指定したパスから最大 levels 段階下の ディレクトリまで探索する (levels は非負の整数)。 -maxdepth 0 は、判別式やアクションの対象にするのは、 コマンドライン引き数だけであることを意味する。

-mindepth levels

コマンドライン引き数として指定したパスから少なくとも levels 段階 ディレクトリを下降するまで、どんな判別式やアクションも行わない (levels は非負の整数)。 -mindepth 1 を指定すると、コマンドラインの引き数を除くすべてファイルを処理する。

-mount
ほかのファイルシステムにあるディレクトリを探索しない。これは -xdev の別名であり、系統の違う find との互換性のためにある。

-noignore_readdir_race
-ignore_readdir_race の効果を無効にする。

-noleaf
「ディレクトリのハードリンク数から 2 を引いたものが、そのディレクトリに 含まれるサブディレクトリの数である」とする最適化動作を行わない。 このオプションが必要になるのは、ディレクトリとリンクの関係について Unix の流儀に従わないファイルシステムを探索するときだ。 たとえば、CD-ROM や MS-DOS のファイルシステムとか、AFS ボリュームの マウントポイントなどを探索するときである。 通常の Unix ファイルシステムでは、各ディレクトリは少なくとも 2 個のハードリンクを持っている。ディレクトリ名のエントリと、 そのディレクトリ中の `.' エントリである。さらに、そのディレクトリに サブディレクトリがあれば、サブディレクトリそれぞれに、親ディレクトリに ハードリンクした '..' エントリが存在する。 find としては、ディレクトリを調べる際に、ディレクトリのリンク数より 2 少ない 数だけサブディレクトリを stat 関数で調べた時点で、ディレクトリ中の 残りのエントリはディレクトリではない (ディレクトリツリー中の `leaf 葉っぱ' ファイルである) とわかるわけである。 もし、調べるのがファイル名だけで充分なら、ファイルに対して stat 関数を 実行する必要はない。そこで、この動作により、検索速度が いちじるしく向上するわけだ。

-regextype type
判別式 -regex と -iregex が理解する正規表現の文法を変更する。 このオプションよりコマンドラインの後方で指定する -regex などに対して効果がある。 現在実装されている文法のタイプには、emacs (デフォルトである), posix-awk, posix-basic, posix-egrep, posix-extended がある。

-version, --version
find のバージョンを表示して終了する。

-warn, -nowarn
警告メッセージの表示、非表示を切り替える。こうしたメッセージは、 もっぱらコマンドラインの使用法に関するものであり、 find がディレクトリを探索中に出会うかもしれない何らかの状況に 関するものではない。デフォルトの動作は、標準入力が tty であれば、 -warn であり、それ以外の場合は、 -nowarn である。

-xdev
ほかのファイルシステムにあるディレクトリを探索しない。

判別式 (TESTS)
判別式の中には、たとえば -newerXY や -samefile のように、現在検査の対象になっているファイルと、コマンドラインで指定した リファレンスファイルとを比較することになっているものがある。 そうしたリファレンスファイルの実体が何になるかは、 -H, -L, -P といったオプションや、先行する -follow の存在によって決まってくる。 ただし、リファレンスファイルが調べられるのは、一回だけであり、 それはコマンドラインの解析が行われるときである。 リファレンスファイルを調べることができない場合は (たとえば、 それに対する stat(2) システムコールに失敗するなど)、エラーメッセージが表示され、 find は 0 以外のステータスで終了する。

数値の引き数は、以下の形で指定することができる。

+n
n を越える数であることを意味する。
-n
n 未満であることを意味する。
n
ぴったり n であることを意味する。

-amin n
ファイルの最終アクセス日時が n 分前であれば真。

-anewer file
ファイルの最終アクセス日時が、file の内容更新日時よりも 新しければ、真を返す。引き数 file がシンボリックリンクで、 しかも -H や -L オプションが有効になっている場合は、リンク先のファイルの内容更新日時が 比較に使用されることになる。

-atime n
ファイルの最終アクセス日時が n 日前ならば、真を返す。 ファイルの最終アクセス日時が何日前かを計算する際、現在時刻との時間差を 24 で割った余りは切り捨てられる。従って、 -atime +1 にマッチするためには、 ファイルは少なくとも二日前にアクセスされていなければならない。

-cmin n
ファイルの最終ステータス変更日時が n 分前ならば真。

-cnewer file
ファイルの最終ステータス変更日時が、file の内容更新日時よりも 新しければ、真を返す。引き数 file がシンボリックリンクで、 しかも -H や -L オプションが有効になっている場合は、リンク先のファイルの内容更新日時が 比較に使用されることになる。

-ctime n
ファイルの最終ステータス変更日時が n 日前ならば、真を返す。 何日前かを計算する際に、現在時刻との時間差を 24 で割った余りを 切り捨てることが、ファイルのステータス変更日時の解釈にどんな影響を 及ぼすかについては、 -atime の説明を見てほしい。

-empty
ファイルが空で、通常のファイルかディレクトリならば真。

-executable
実行可能なファイルや (ファイル名解決の際に) 検索可能なディレクトリに マッチする。判別式 -perm が ACL (アクセス・コントロール・リスト) などのパーミッション制御の 仕組みを無視するのに対して、この判別式は ACL なども考慮に入れる。 この判別式は access(2) システムコールを使用しているので、UID マッピング (または root-squashing) を 行っている NFS サーバがあると、正確な結果を得られないことがある。 なぜなら、たいていのシステムは access(2) をクライアントのカーネルで実装しており、それ故、サーバ側に保持されている UID マッピング情報を利用できないからだ。 この判別式はひとえに access(2) システムコールの結果に基づいているので、この判別式が 真を返したからと言って、そのファイルが実際に実行できるとはかぎらない。

-false
常に偽を返す。

-fstype type
ファイルが置かれているファイルシステムが type ならば、真を返す。 使用できるファイルシステムは、Unix の系統によって様々である。 Unix の系統次第では指定可能なファイルシステムを不完全ながら挙げると、 ufs, 4.2, 4.3, nfs, tmp, mfs, S51K, S52K などがある。 アクション -printf で書式指定子 %F を使えば、使用中のファイルシステムのタイプが何かを知ることができる。

-gid n
ファイルのグループ ID 番号が n ならば真。

-group gname
ファイルの属するグループが gname ならば真 (グループ ID 番号で 指定してもよい)。

-ilname pattern
-lname と同じだが、大文字小文字を区別しない。 -L か -follow オプションが有効な場合は、シンボリックリンクがリンク切れしている場合を除き、 この判別式は偽を返す。

-iname pattern
-name と同じだが、大文字小文字を区別しない。 たとえば、パターン `fo*' や `F??' は、`Foo', `FOO', `foo', `fOo' といったファイル名とマッチする。シェルのファイル名展開と違い、 こうしたパターンにおいて '*' は、ファイル名の先頭にある '.' とも マッチする。すなわち、 find -name *bar は、ファイル `.foobar' ともマッチすることになるわけだ。 当然ながら、パターンは引用符で囲むべきだということに気をつけて いただきたい。さもないと、パターン中にワイルドカード文字があれば、 シェルがそれを展開してしまうことになる。

-inum n
ファイルの inode 番号が n ならば真。たいていの場合、 この判別式より、 -samefile を使った方が簡単である。

-ipath pattern
-iwholename と同じように動作する。この判別式は非推奨である。使わないでいただきたい。

-iregex pattern
-regex と同じだが、大文字小文字を区別しない。

-iwholename pattern
-wholename と同じだが、大文字小文字を区別しない。

-links n
ファイルのリンク数が n ならば真。

-lname pattern
ファイルがシンボリックリンクであり、リンク先として指定されているパスが シェルのパターン pattern にマッチすれば、真を返す。 メタ文字は、`/' や `.' を例外扱いしない。 -L や -follow オプションが有効な場合は、シンボリックリンクがリンク切れしている場合を除き、 この判別式は偽を返す。

-mmin n
ファイルの最終内容更新日時が n 分前であれば真。

-mtime n
ファイルの最終内容更新日時が n 日前ならば、真を返す。 何日前かを計算する際に、現在時刻との時間差を 24 で割った余りを 切り捨てることが、ファイルの内容更新日時の解釈にどんな影響を 及ぼすかについては、 -atime の説明を見てほしい。

-name pattern
ファイルやディレクトリのベースネーム (パスから最後の要素だけを残して、 先行するディレクトリを取り去ったもの) が、シェルのパターン pattern に マッチすれば、真を返す。メタ文字 (`*', `?', `[]) は、 ベースネームの先頭にある `.' とマッチする (findutils-4.2.2 から このように変更になった。下記のセクション「標準への準拠」を参照)。 あるディレクトリとそれ以下にあるファイルをまとめて無視するには、 -prune を使うとよい。一例が -path の説明中にある。 中カッコ ('{}') は特殊文字として認識されない。この点、bash を含む 一部のシェルで、シェル・パターン中の中カッコに特別な意味を付与しているのと 異なっている。ファイル名のマッチングは、 fnmatch(3) ライブラリ関数を用いて行われる。パターンを引用符で囲むのを 忘れないように。シェルによって展開されてしまわないようにするためである。

-newer file
ファイルが file よりも最近に内容を更新されていれば、真を返す。 引き数 file がシンボリックリンクで、しかも -H や -L オプションが有効になっている場合は、 リンク先のファイルの内容更新日時が比較に使用されることになる。

-newerXY reference
目下検査の対象になっているファイルのタイムスタンプを reference と 比較する。引き数 reference は、たいていの場合ファイル名であるが (そして、そのタイムスタンプの一つが 比較に使用されるが)、日時を直接表す文字列でも構わない。 X と Y は仮の表現であって、実際には以下に述べるような別の文字が来る。 そうした文字が、検査の対象になっているファイルとリファレンスそれぞれの、 どの日時を比較に使用するかを決めるのである (訳注: 前者を X で、 後者を Y で指定する)。
a ファイルのアクセス日時
B ファイルの作成日時
c inode のステータスが変更された日時
m ファイルの内容が更新された日時
t reference が日時の直接表現として解釈される

組み合わせによっては、無効なものもある。たとえば、 X に t を指定しても無効である。 組み合わせの中には、すべてのシステムで実装されているとはかぎらない ものもある。たとえば、 B はすべてのシステムでサポートされているわけではない。 XY の無効な組み合わせやサポートされていない組み合わせを指定すると、 致命的エラーが起きる。日時を直接指定すると、それは GNU date の -d オプションに対する引き数と同様に解釈される。 リファレンスファイルの作成日時を使用しようとして、作成日時が 特定できない場合は、致命的エラーのメッセージが表示される。 また、検査対象になるファイルの作成日時を参照する判別式を指定した場合、 作成日時がわからない環境では、そのテストはどのファイルに対しても 失敗することになる。

-nogroup
ファイルのグループ ID 番号に対応するグループが存在しなければ真。

-nouser
ファイルのユーザ ID 番号に対応するユーザが存在しなければ真。

-path pattern
ファイル名がシェルのパターン pattern にマッチすれば真。 メタ文字は `/' や `.' を例外扱いしない。従って、たとえば、
find . -path "./sr*sc"
は、`./src/misc' と言うディレクトリを (存在していれば) 表示する。 あるディレクトリ以下をすべて無視するには、そこに存在するファイルを 一つ一つ抑止するよりも、 -prune を使用した方がよい。たとえば、 `src/emacs' と、その下にあるファイルや ディレクトリのすべてをスキップし、それ以外のファイルがあったら、 その名前を表示するとしよう。そのためには、こんな風にする。
find . -path ./src/emacs -prune -o -print
パターンマッチのテストは、パスを含むファイル名の全体に対して行われるが、 そうしたパス付きのファイル名は、コマンドラインで指定した探索の始点の一つから 始まっていることに注意してほしい。だから、 -path の引き数に絶対パス名を使用することに意味があるのは、関連する探索の 始点がこちらも絶対パスであるときだけだろう。従って、次のコマンドは 何にもマッチしないことになる。
find bar -path /foo/bar/myfile -print
述語 -path は、HP-UX の find でもサポートされている。 POSIX 標準の次期バージョンでも採用されることになるだろう。

-perm mode
ファイルの許可属性が mode (8 進数表現でもシンボル表現でもよい) とまったく同じなら、真を返す。 mode 指定のこの形式では、許可属性がぴったり一致することを 要求しているので、シンボルによる表現でこの形式を使おうとすると、 かなり複雑なモード文字列を指定しなければならないかもしれない。たとえば -perm g=w は、許可属性が 0020 のファイルにしかマッチしないことになる (すなわち、許可属性のうち、グループの書き込み許可のみが立っている ファイルだ)。そんなわけで、mode の前に `/' や `-' を付ける形式を 使いたくなる場合の方が、ずっと多そうである。たとえば、 -perm -g=w なら、グループが書き込み許可を持っているいかなるファイルにも マッチするわけだ。具体例については「用例」セクションを見てほしい。

-perm -mode
mode で指定した許可属性ビットのすべてが、ファイルでも立っていれば、 真を返す。mode 指定のこの形式でも、シンボルによる許可属性表現が 使用できる。と言うより、この形式ではたいていの場合、シンボルによる表現を 使いたくなるだろう。 シンボルによる表現を使用する場合は、`u' や `g' や `o' を きちんと指定しなければならない。具体例については「用例」セクションを 見てほしい。

-perm /mode
mode で指定した許可属性ビットのどれかが、ファイルでも立っていれば、 真を返す。mode 指定のこの形式でも、シンボルによる許可属性表現が 使用できる。シンボルによる表現を使用する場合は、`u' や `g' や `o' を きちんと指定しなければならない。具体例については「用例」セクションを 見てほしい。 mode で許可属性ビットが一つも立っていない場合、この判別式は いかなるファイルにもマッチする (すなわち、 -perm -000 の動作と同じだということだ)。

-perm +mode
非推奨な形式。mode で指定した許可属性ビットのどれかが立っている ファイルを捜す古い方法である。代わりに -perm /mode を使用した方がよい。`+' を付けて mode を指定するこの形式で シンボルによる表現を使おうとすると、思いがけない結果を生むことがある。 たとえば、 `+u+x' はそれ自体有効なシンボル表現である ('+u,+x' と 同じであり、0111 を意味する)。そのため、 -perm +u+x は、 -perm +mode として評価されず、ぴったり一致する許可属性を指定するときの -perm mode として評価されてしまうのだ。その結果、実行ビットが少なくともどれか一つ 立っているファイルではなく、許可属性がぴったり 0111 のファイルに マッチすることになる。もし、この項の説明がわかりにくかったとしても、 あなた一人がわからないのではない。とりあえず、 -perm /mode を使っておいていただきたい。判別式 -perm のこの形式が非推奨なのは、シンボルによる許可属性に先行する `+' は、 シンボル表現の一部として解釈するように POSIX の規定で要求されて いるからであり、それ故、我々は '+' に代えて、'/' を使うようにしたのである。

-readable
読み込み可能なファイルにマッチする。判別式 -perm が ACL (アクセス・コントロール・リスト) などのパーミッション制御の 仕組みを無視するのに対して、この判別式は ACL なども考慮に入れる。 この判別式は access(2) システムコールを使用しているので、UID マッピング (または root-squashing) を行っている NFS サーバがあると、正確な結果を 得られないことがある。なぜなら、たいていのシステムは access(2) をクライアントのカーネルで実装しており、それ故、サーバ側に保持されている UID マッピング情報を利用できないからである。

-regex pattern
ファイル名が正規表現 pattern にマッチすれば、真を返す。 これはパスを含むファイル名全体に対するマッチであって、部分的な一致ではない。 だから、たとえば、`./fubar3' という名前のファイルにマッチさせるために、 正規表現 `.*bar.' や `.*b.*3' は使用できるが、`f.*r3' は使用できないわけだ。 find が理解する正規表現は、デフォルトでは Emacs の正規表現だが、これは -regextype オプションで変更することができる。

-samefile name
ファイルが name と同じ inode を参照していれば、真を返す。 -L が有効な場合、シンボリックリンクも真を返す。

-size n[cwbkMG]
ファイルが n 単位分の領域を使用していれば、真を返す。 以下の接尾辞が使える。

`b'
単位はブロック。1 ブロックは 512 バイト。(これが接尾辞を使わないときの デフォルトである)
`c'
単位はバイト。
`w'
単位はワード。1 ワードは 2 バイト。
`k
単位はキロバイト (1 キロバイトは 1024 バイト)。
`M'
単位はメガバイト (1 メガバイトは 1048576 バイト)。
`G'
単位はギガバイト (1 ギガバイトは 1073741824 バイト)。

サイズには間接ブロック (indirect block) の分は含まれないが、 穴空きファイル (sparse file) における、実際には割り当てられていない ブロックの分は含まれる。アクション -printf の `%k' や `%b' 書式指定子とは穴空きファイルの扱い方が違うことを、 心にとめておいてほしい。接尾辞 `b' は常に 512 バイトのブロックを 意味し、1 キロバイトのブロックを指すことはない。その点が、アクション -ls の動作と異なっている。

-true
常に真。

-type c
ファイルのタイプが c であれば真。c の位置には実際には 以下の文字が来る。

b
ブロック・スペシャルファイル (バッファあり)
c
キャラクタ・スペシャルファイル (バッファなし)
d
ディレクトリ
p
名前付きパイプ (FIFO)
f
通常のファイル
l
シンボリックリンク。オプション -L や -follow が有効な場合、シンボリックリンクがリンク切れの場合を除いて、 この判別式が真になることはない。 -L が有効なときにシンボリックリンクを検索したかったら、 -xtype を使うべきである。
s
ソケット
D
ドア (Solaris の場合)

-uid n
ファイル所有者のユーザ ID 番号が n ならば真。

-used n
ファイルが最後にアクセスされたのが、ファイルのステータスが最後に 変更されてから n 日後ならば、真を返す。

-user uname
ファイルの所有者が uname というユーザならば真 (ユーザ ID 番号で指定してもよい)。

-wholename pattern
-path と同じである。この別名は移植性で -path に劣る。

-writable
書き込み可能なファイルにマッチする。判別式 -perm が ACL (アクセス・コントロール・リスト) などのパーミッション制御の 仕組みを無視するのに対して、この判別式は ACL なども考慮に入れる。 この判別式は access(2) システムコールを使用しているので、UID マッピング (または root-squashing) を行っている NFS サーバがあると、正確な結果を 得られないことがある。なぜなら、たいていのシステムは access(2) をクライアントのカーネルで実装しており、それ故、サーバ側に保持されている UID マッピング情報を利用できないからである。

-xtype c
検査の対象となるファイルがシンボリックリンクでないかぎり、 -type と同じである。ファイルがシンボリックリンクのときは、以下のように動作する。 -H や -P オプションが指定された場合は、リンク先の ファイルのタイプが c ならば、真を返す。他方、 -L オプションが指定されている場合は、c が `l' ならば、真を返す。 言い換えると、ファイルがシンボリックであるとき、 -xtype は、 -type が検査しない方のファイルのタイプを検査するわけだ。

アクション

-delete
ファイルを消去する。消去に成功すれば、真を返す。消去に失敗した場合は、 エラーメッセージを表示する。 -delete に失敗した場合の find の終了ステータスは、ゼロ以外である (最終的に終了したときの 終了ステータスのことである)。 -delete を使用すると、自動的に -depth オプションが有効になる。

警告: 忘れないでほしいが、find のコマンドラインは一つの式 (expression) として 評価されるので、一番最初に -delete を指定すると、 find は、指定された探索の開始点以下にあるものを、ことごとく消去しようとする。 後で -delete を付けて使用するつもりで、 find のコマンドラインをテスト実行するときは、 -depth を明示的に指定するとよい。そうすれば、後で「こんなはずではなかった」と 慌てないですむ。 -delete を指定すると自動的に -depth が有効になるので、 -prune を -delete と一緒に使っても役に立たない。

-exec command ;
command を実行する。command の返り値が 0 ならば、真を返す。 find のコマンドラインで指定されたこれ以降の引き数は、`;' という引き数が現れるまで、 すべてコマンドに対する引き数と見なされる。文字列 `{}' は、 それがコマンドの引き数中に現れるすべての場所で、現在処理中のファイル名に 置き換えられる。 find の一部の版とは違い、`{}' は引き数中の一ヶ所でしか使えないわけではない。 こうした構文の要素 (訳注: すなわち、`{}' と `;') は、シェルによって 展開されないように、どちらも `\' でエスケープするなり、 引用符で囲むなりする必要があるかもしれない。アクション -exec の使用例については「用例」セクションを見てほしい。 指定したコマンドは、マッチした各ファイルに対して一回づつ実行される。 また、コマンドは find を実行したディレクトリで実行される。そこで、 -exec アクションの使用に関しては、セキュリティの問題が避けられないわけだ。 -exec の代わりに、 -execdir アクションを使用することをお勧めする。 (訳注: `;' は引き数なので、直前の引き数との間に空白が必要だ ということに注意してほしい。)

-exec command {} +
アクション -exec のこの変形も、選択したファイルに対して指定したコマンドを実行するが、 コマンドラインを形成するとき、選択した各ファイル名をコマンドラインの末尾に 追加して行くという方法を取る (訳注: コマンドラインが長くなりすぎるときは、 処理するファイル名の数を適切に分割して、コマンドを複数回実行する)。 そのため、コマンドを呼び出す回数は、マッチしたファイルの数より ずっと少なくてすむわけだ。コマンドラインの形成法は、 xargs のコマンドライン形成法とほぼ同じである。`{}' はコマンドライン中の 一ヶ所でしか使えない。コマンドは find を実行したディレクトリで実行される。 (訳注: `+' は引き数なので、直前の引き数との間に空白が必要だ ということに注意してほしい。)

-execdir command ;
-execdir command {} +
-exec と似ているが、指定したコマンドはマッチしたファイルが存在するサブディレクトリで 実行される。そのサブディレクトリは、 find を実行したディレクトリとは違うのが普通だ。 これはコマンドを呼び出す方法としてずっと安全である。マッチしたファイルの パスを解決する際に、競合状態が起きるのを避けられるからだ。 アクション -exec の場合と同様、 -execdir の `+' を伴う形式でも、 マッチした複数のファイルを一度に処理するように、コマンドラインを 形成することになる。しかし、 command のどの呼び出しにおいても、処理の対象としてリストされるファイルは、 同じサブディレクトリに存在するものだけである。このアクションを 使用するのなら、環境変数 $PATH が `.' を参照しないようにしなければならない。 さもないと、悪意を持った攻撃者が、あなたが -execdir を実行することになるディレクトリに適当な名前のファイルを 入れておくことによって、何でも好きなコマンドを実行できてしまうからである。 $PATH の中に、空っぽのエントリや、絶対パスのディレクトリ名ではない エントリがある場合にも、同じことが当てはまる。

-fls file
真を返す。 -ls と似ているが、 -fprint 同様、出力を file に書き出す点が違う。 出力用のファイルは、この述語の対象になるものが一つもなかった場合でも、 必ず作成される。 ファイル名中の変わった文字がどのように扱われるかについては、 「変わり者のファイル名」セクションを参照してほしい。

-fprint file
真を返す。パス付きのファイル名をファイル file に出力する。 find の実行時に file が存在しなければ、 新たに作成される。すでに存在していれば、元の中身が捨てられる。 ファイル名 ``/dev/stdout'' と ``/dev/stderr'' の扱いは特別で、 それぞれ標準出力と標準エラー出力を指している。 出力用のファイルは、この述語の対象になるものが一つもなかった場合でも、 必ず作成される。 ファイル名中の変わった文字がどのように扱われるかについては、 「変わり者のファイル名」セクションを参照してほしい。

-fprint0 file
真を返す。 -print0 と似ているが、 -fprint 同様、出力を file に書き出す点が違う。 出力用のファイルは、この述語の対象になるものが一つもなかった場合でも、 必ず作成される。 ファイル名中の変わった文字がどのように扱われるかについては、 「変わり者のファイル名」セクションを参照してほしい。

-fprintf file format
真を返す。 -printf と似ているが、 -fprint 同様、出力を file に書き出す点が違う。 出力用のファイルは、この述語の対象になるものが一つもなかった場合でも、 必ず作成される。 ファイル名中の変わった文字がどのように扱われるかについては、 「変わり者のファイル名」セクションを参照してほしい。

-ls
真を返す。処理対象のファイルを ls -dils の書式で標準出力にリストする。ブロック数は、1 ブロック 1 キロバイトの 計算である。ただし、環境変数 POSIXLY_CORRECT が設定されている場合は、 1 ブロック 512 バイトが使用される。 ファイル名中の変わった文字がどのように扱われるかについては、 「変わり者のファイル名」セクションを参照してほしい。

-ok command ;
-exec と似ているが、まずユーザに問い合わせを行う。ユーザーが同意すれば、 コマンドを実行する。同意しなければ、何もせずに偽を返す。 コマンドを実行する際、そのコマンドの標準入力は、 /dev/null に付け換えられる。

プロンプトに対するユーザの応答は、肯定・否定を表す一組の正規表現と照合して、 同意か、不同意かが判断される。この正規表現は、環境変数 `POSIXLY_CORRECT' が 設定されていれば、システムから得られるが、設定されていなければ、 find のメッセージ・カタログから取得される。なお、システムに適切な定義が 存在しない場合は、 find の持つ定義が使用されることになる。どちらの場合でも、正規表現そのものの 解釈は、環境変数 'LC_CTYPE' (文字クラスにについて) や 'LC_COLLATE' (文字の範囲や等価クラスについて) の影響を受ける。

-okdir command ;
-execdir と似ているが、 -ok と同じように、まずユーザに問い合わせを行う。 ユーザが同意しなければ、何もせずに偽を返す。 コマンドを実行する際、そのコマンドの標準入力は、 /dev/null に付け換えられる。

-print
真を返す。パス付きのファイル名を標準出力に表示し、各ファイル名の後ろに 改行文字を付ける。 find の出力をパイプを使って他のプログラムに渡している場合、検索対象の ファイル名に改行文字が含まれている可能性が、わずかにでもあるならば、 アクション -print ではなく、 -print0 を使用することを真剣に考えるべきだ。 ファイル名中の変わった文字がどのように扱われるかについては、 「変わり者のファイル名」セクションを参照してほしい。

-print0
真を返す。パス付きのファイル名を標準出力に表示し、各ファイル名の後ろに (-print が改行文字を付けるのとは違って) ヌル文字を付加する。 そうすることによって、find の出力を処理するプログラムが、 改行文字などのホワイトスペースを含むファイル名を正しく解釈できる ようになるわけだ。このアクションは、 xargs の -0 オプションに呼応している。

-printf format
真を返す。標準出力に format を出力する。 そのとき format 中の `\' によるエスケープシーケンスと、`%' に 始まる書式指定子を認識して変換する。 フィールドの幅や精度は、C 言語の `printf' 関数と同じやり方で 指定できる。フィールドの多くは、(`printf' 関数流に言うと) %d ではなく、%s として出力されることに注意していただきたい。 すなわち、フラグが期待通りに効かないかもしれないのだ。だが、 それはまた、`-' フラグ (フィールドを強制的に左揃えにする) が 使えるということでもある。 -print とは違って、 -printf は文字列の末尾に改行文字を付加しない。 バックスラッシュ・エスケープシーケンスと書式指定子は以下のとおりである。

\a
警告ベル。
\b
バックスペース。
\c
このフォーマットによる出力をただちに停止し、出力バッファを フラッシュする。
\f
フォームフィード文字。
\n
改行文字。
\r
復帰文字。
\t
水平タブ。
\v
垂直タブ。
\0
ASCII NUL 文字。
\\
バックスラッシュ文字そのもの (`\')。
\NNN
ASCII コードが NNN (8 進数) の文字。

バックスラッシュ文字 `\' に上記以外の文字が続く場合、`\' は 普通の文字として扱われる。従って、二文字とも表示されるわけだ。

%%
パーセント文字そのもの。
%a
ファイルの最終アクセス日時を C 言語の `ctime' 関数が返す形式で表示する。
%Ak
ファイルの最終アクセス日時を k で指定した書式で表示する。 k には `@' か、あるいは C 言語の `strftime' 関数の書式指定子を用いる。 k に指定可能な値を以下に列挙する。 一部のものは使えないシステムがあるかもしれないが、それはシステム間での `strftime' の非互換性による。

@
Jan. 1, 1970, 00:00 GMT からの経過秒数。小数点以下も表示する。

時刻フィールド:

H
時 (00..23)
I
時 (01..12)
k
時 ( 0..23)
l
時 ( 1..12)
M
分 (00..59)
p
現在のロケールにおける AM/PM の相当語
r
12 時間制の時刻 (hh:mm:ss [AP]M)
S
秒 (00.00 .. 61.00)。小数点以下も表示。
T
24 時間制の時刻 (hh:mm:ss)
+
日付と時刻。両者の間は `2004-04-28+22:22:05.0' といった具合に '+' で 区切られる。これは GNU の拡張である。日時は現在のタイムゾーンのものが 使われる (それ故、環境変数 TZ の設定によって変わるかもしれない)。 秒には小数点以下も付く。
X
現在のロケールによる時刻表示 (H:M:S)
Z
タイムゾーン (JST など)。タイムゾーンを決定できない場合は、何も表示しない。

日付フィールド:

a
現在のロケールによる曜日の短縮形 (Sun..Sat)
A
現在のロケールによる曜日のフル表示。長さは可変 (Sunday..Saturday)
b
現在のロケールによる月名の短縮形 (Jan..Dec)
B
現 在 のロケールによる月名のフル表示。長さは可変 (January..December)
c
現在のロケールによる日付と時刻の表示 (Sat Nov 04 12:02:33 EST 1989)。 この表示形式は ctime(3) のものと同じであり、 ctime(3) の形式との互換性を維持するためにそうなっている。秒には小数点以下が付かない。
d
その月の何日目かの表示 (01..31)
D
日付 (mm/dd/yy)
h
b と同じ
j
その年の何日目かの表示 (001..366)
m
月 (01..12)
U
その年の何週目か (日曜日を週の始まりとする) (00..53)
w
その週の何日目か (0..6)
W
その年の何週目か (月曜日を週の始まりとする) (00..53)
x
現在のロケールによる日付表示 (mm/dd/yy)
y
年の後ろ二桁 (00..99)
Y
年 (1970...)

%b
ファイルのディスクスペース使用量を 1 ブロック 512 バイトのブロック数で 表示する。割り当てられたディスクスペースは、ファイルシステムの ブロックサイズの倍数になるので、この表示はたいてい %s/512 より大きい。 だが、ファイルが穴空きファイル (sparse file) の場合は、%s/512 より 小さくなることもある。
%c
ファイルの最終ステータス変更日時を C 言語の `ctime' 関数が返す 形式で表示する。
%Ck
ファイルの最終ステータス変更日時を k で指定した書式で表示する。 k は %A の場合と同じである。
%d
ファイルがディレクトリツリー中でどの深さにあるかを示す。0 だったら、 そのファイルがコマンドライン引き数であるということだ。
%D
ファイルがどのデバイス上にあるかを十進数のデバイス番号で示す (stat 構造体の st_dev フィールドに当たる)。
%f
先行するディレクトリをすべて取り去ったファイル名 (すなわち、 最後の要素のみ表示)。
%F
ファイルが置かれているファイルシステムのタイプ。 ここで表示された値は -fstype の引き数に指定することができる。
%g
ファイルのグループ名。グループ名が登録されていない場合は、 グループ ID 番号。
%G
ファイルのグループ ID 番号。
%h
ファイル名中の先行するディレクトリの部分 (すなわち、 最後の要素以外のすべて)。ファイル名にスラッシュが一つも含まれない場合は (ファイルがカレントディレクトリにあるからだ)、 %h 書式指定子は "." に展開される。
%H
探索の開始点を示すコマンドライン引き数で、その下に問題のファイルが 見つかったもの。
%i
ファイルの inode 番号 (十進数表示)。
%k
ファイルのディスクスペース使用量を 1 ブロック 1 キロバイトのブロック数で 表示する。割り当てられたディスクスペースは、ファイルシステムの ブロックサイズの倍数になるので、この表示はたいてい %s/1024 より大きい。 だが、ファイルが穴空きファイル (sparse file) の場合は、%s/1024 より 小さくなることもある。
%l
シンボリックリンクの参照先 (ファイルがシンボリックリンクでなかったら、 空文字列)。
%m
ファイルの許可属性ビット (8 進数表示)。このオプションが使用している 数値は、Unix のたいていの実装が使用している「伝統的な」数値である。 しかし、ご使用のシステムの実装では、8 進数で表示する許可属性ビットの並び方が 独特かもしれない。その場合は、ファイルの許可属性の実際の値と %m の出力とが、相違することになる。この数値の先頭に 0 を付けて 表示したいこともよくあるが、そのためには、 # フラグを使用すればよい (たとえば、`%#m' といった具合に)。
%M
ファイルの許可属性 (ls と同様のシンボルによる表現)。この書式指定子は findutils 4.2.5 以来 サポートされている。
%n
ファイルのハードリンク数。
%p
ファイル名。
%P
問題のファイルが、ある探索開始点の下にあった場合に、ファイル名から 探索開始点を示すコマンドライン引き数の部分を取り去ったもの。
%s
バイトで表示したファイルサイズ。
%S
ファイルの穴空き率 (sparseness)。この値は、(BLOCKSIZE*st_blocks / st_size) で 計算される。ある大きさの普通のファイルから得られる値は、 厳密に言うと、システム依存である。それでも、 穴空きファイルの穴空き率は、通常 1.0 未満になるし、間接ブロックを 使用しているファイルの穴空き率は、1.0 以上になることがある。 BLOCKSIZE に使われる値は、システム次第だが、普通は 512 バイトである。 ファイルサイズが 0 の場合、出力される値は不定である。 st_blocks をサポートしていないシステムでは、ファイルの穴空き率は、 1.0 と見なされる。
%t
ファイルの最終内容更新日時を、C 言語の `ctime' 関数が返す形式で表示する。
%Tk
ファイルの最終内容更新日時を、k で指定した書式で表示する。 k は %A の場合と同じである。
%u
ファイルの所有者名。所有者のユーザが登録されていない場合は、ユーザ ID 番号。
%U
ファイルのユーザ ID 番号。
%y
ファイルのタイプ (ls -l の表現とほぼ同じ)。U=unknown type (これが表示されることはないはずだ)
%Y
ファイルのタイプ (表示は %y と同じ)。ただし、シンボリックリンクをたどる。 その場合、L=loop, N=nonexistent である。

一個の `%' に上記以外の文字が続く場合、`%' 文字は捨てられるが、 それに続く文字は表示される (書式指定文字が新たに追加されるかもしれないので、 この動作を当てにしてはいけない)。書式指定の末尾に `%' があるときの動作は、 続く文字がないので不定である。ロケールによっては、お宅のドアの鍵が 見つからなくなるかもしれない。また、別のロケールでは、 お読みの小説の最後のページが消えてしまうかもしれない。

書式指定子 %m と %d はフラグ #, 0, + をサポートするが、それ以外の書式指定子は、数値を表示する場合でも、 そうしたフラグをサポートしない。 # などをサポートしない数値関係の書式指定子には、 G, U, b, D, k, n などがある。しかし、書式フラグ `-' はサポートされており、フィールドを (デフォルトの) 右揃えから左揃えに変更する。

ファイル名中の変わった文字がどのように扱われるかについては、 「変わり者のファイル名」セクションの説明を参照してほしい。

-prune
真を返す。ファイルがディレクトリの場合は、そのディレクトリ以下に 降りて行かない。 -depth が指定してあるときは、偽を返し、何もしない。 -delete を指定すると自動的に -depth が有効になるので、 -prune を -delete と一緒に使っても役に立たない。

[訳注]:
バージョン 4.4.0 以降の find では、-prune の動作が 上記の説明と少し異なっている。すなわち、「-depth が指定して あるときは、何もしない」のは、それまでのバージョンと同じだが、 返り値は真を返している。ご自分で、 find . -depth -path "./foo" -prune -print などを実行して、確認していただきたい。-prune が真を返していれば、 ディレクトリ ./foo が表示されるはずだ。

-quit
直ちに終了する。動いている子プロセスを残したまま終了したりはしないが、 コマンドラインで指定したパスをこれ以上処理することはない。たとえば、 find /tmp/foo /tmp/bar -print -quit は、 /tmp/foo を表示するだけである。 -execdir ... {} + によってすでに作成されたコマンドラインがあれば、 find が終了する前に、呼び出して実行する。終了ステータスは、 エラーがすでに起きているかどうかよって、0 のことも、0 でないこともある。

変わり者のファイル名
多くの場合、 find のアクションはデータを端末に表示することになるわけだが、それは ほかのユーザが自由にできるデータであることもある。そうしたデータとは、 たとえば、ファイルの名前、サイズ、内容更新日時などだ。 この内、ファイル名は `\0' と `/' 以外のどんな文字でも使えることに なっているので、時として問題の種となる。ファイル名の中に 風変わりな文字があると、使用している端末に思いがけない、 そしてしばしば望ましくない影響をもたらすことがあるのだ (たとえば、 端末によっては、ファンクション・キーの現在の設定が変更されてしまう)。 風変わりな文字をどう扱うかはアクションによって異なっている。 それを以下に示そう。

-print0, -fprint0
常にファイル名に手を加えず、そのまま出力する。出力先が端末であっても、 同じである。

-ls, -fls
風変わりな文字は、常にエスケープされる。ホワイトスペース (空白、 改行、タブなど)、バックスラッシュ、ダブルクォートは C 言語式の エスケープ表現で出力される (たとえば `\f', `\"')。 ほかの風変わりな文字には、エスケープした8 進数が使われる。 それ以外の表示可能な文字は (-ls や -fls とっては 8 進数の 041 から 0176 に当たる文字)、手を加えずに そのまま出力される。

-printf, -fprintf
出力先が端末でない場合は、そのまま出力される。端末の場合は、 使用される書式指定子によって、結果は様々である。 書式指定子 %D, %F, %g, %G, %H, %Y, %y が展開される値は、 ファイルの所有者の管轄外なので、そのまま出力される。 書式指定子 %a, %b, %c, %d, %i, %k, %m, %M, %n, %s, %t, %u, %U の 値は、ファイル所有者の管轄内であるが、それを使って端末に勝手なデータを 送ることはできない。従って、そのまま出力される。 書式指定子 %f, %h, %l, %p, %P はクォートされる。このクォート方法は、GNU ls と同じである。言い換えると、 -ls や -fls におけるクォート方法とは違うということだ。 もし、 find の出力に使う形式を自由に決めることができるならば、たいていの場合、 終端文字に改行ではなく、`\0' を使用した方がよい。 ファイル名には空白や改行が含まれていることがあるからだ。 どの文字がクォートを必要とするかを判断するには、環境変数 `LC_CTYPE' の設定が 使用される。

-print, -fprint
クォートは -printf や -fprintf と同じやり方で行われる。 find をスクリプト中で使っている場合や、マッチするファイルが行儀の悪い ファイル名を持っている可能性がある場合は、 -print ではなく、 -print0 の使用を考えた方がよいだろう。

アクション -ok と -okdir は、対象となるファイル名をそのまま手を加えずに出力する。この動作は、 将来のリリースで変わるかもしれない。

演算子

演算子を優先順位の高いものから順に列挙する。

( expr )
カッコの内側を先に処理する。カッコはシェルにとって特別な意味を 持っているので、普通はクォートする必要があるだろう。 このマニュアルページで挙げている例の多くでは、そのためにバックスラッシュを 使っている。すなわち `(...)' ではなく、`\(...\)' と書いているわけだ。

! expr
expr が偽の場合、真になる。通常この記号も、シェルによって 解釈されないようにする必要があるだろう。

-not expr
! expr と同じだが、POSIX 準拠の表現ではない。

expr1 expr2
連続する二つの式は、and 結合と解釈される (明示されていないが、 式の間に "-a" があると見なされるわけだ)。expr1 が偽の場合、 expr2 は評価されない。

expr1 -a expr2
expr1 expr2 と同じ。

expr1 -and expr2
expr1 expr2 と同じだが、POSIX 準拠の表現ではない。

expr1 -o expr2
or 結合である。expr1 が真ならば、expr2 は評価されない。

expr1 -or expr2
expr1 -o expr2 と同じだが、POSIX 準拠の表現ではない。

expr1 , expr2
リストである。常に expr1 と expr2 の両方が評価される。 expr1 の値は捨てられ、expr2 の値がリスト全体の値になる。 コンマ演算子はいくつかの異なったタイプの対象を捜すとき便利だが、 ファイルシステム階層の探索は一度しか行われない。 異なった形でマッチした対象の一覧をそれぞれ別のファイルに書き出すには、 -fprintf を利用すればよい。

[訳注]:
find にとって演算子も引き数である。だから `(', `)', `!', `,' といった演算子も、 前後の引き数との間に空白が必要だということに気をつけてほしい。

標準への準拠
POSIX 標準にできるだけ準拠した動作を求めるのなら、環境変数 POSIXLY_CORRECT を設定するとよい。以下のオプションや述語は POSIX standard (IEEE Std 1003.1, 2003 Edition) で規定されている。

-H
このオプションはサポートしている。

-L
このオプションもサポートしている。

-name
この述語はサポートしている。しかし、POSIX への準拠度は、システムの fnmatch(3) ライブラリ関数がどの程度 POSIX に準拠しているかに依存している。 findutils-4.2.2 以来、シェルのメタ文字 (`*', `?', `[]' など) は、 ファイル名の先頭の `.' 文字にマッチするが、 これは IEEE PASC interpretation 126 がそう要求しているからである。 この動作は それ以前のバージョンの findutils と異なっている。

-type
サポートしている。POSIX では `b', `c', `d', `l', `p', `f', `s' を 規定している。GNU find は、そのほか「ドア」を表す `D' もサポートしているが、 使えるのは OS がそうしたファイル・タイプを用意している場合のみである。

-ok
サポートしている。プロンプトに対する応答は、"yes"、"no" を表すパターンに 照らして解釈されるが、そのパターンは環境変数 `LC_MESSAGES' の設定によって 選択されたものである。 環境変数 `POSIXLY_CORRECT' が設定されている場合は、 何が肯定的応答 (yes) で、何が否定的応答 (no) かを決めているシステムの 定義が、このパターンに使用される。nl_langinfo(3) に関する システムの文書、特に YESEXPR と NOEXPR の部分を参照してほしい。 `POSIXLY_CORRECT' が設定されていない場合は、パターンは、システムではなく、 find 自身のメッセージ・カタログから取得される。

-newer
サポートしている。指定されたファイルがシンボリックリンクの場合は、 必ずリンク先が参照される (訳注: 訳者としては、-P、-L、 -H オプションの説明から言って、「-L や -H オプションが 有効な場合は」という条件が必要ではないかと思う)。以前のバージョンでは、 シンボリックリンクそのものから比較に使う日時を取得していたのだが、 動作がこのように変更になった。後述の「履歴」セクションも参照してほしい。

-perm
サポートしている。環境変数 POSIXLY_CORRECT が設定されていない場合は、 POSIX では無効な +a+x といったモード指定の引き数も、 後方互換のために使用できるようになっている。

その他の述語
-atime, -ctime, -depth, -group, -links, -mtime, -nogroup, -nouser, -print, -prune, -size, -user -xdev といった述語は、すべてサポートしている。

POSIX 標準は、カッコ `(', `)'、否定 `!'、それに and と or 演算子 (-a, -o) を規定している。

上記以外のすべてのオプション、述語、式などは、POSIX 標準にない拡張である。 とは言え、そうした拡張の多くは、GNU find に特有なものではない。

POSIX 標準によれば、 find はループを検出することになっている。

find ユーティリティは無限ループを検出しなければならない。無限ループとは、 探索中に入ったディレクトリが、すでに探索済みで、最後に処理の対象にした ファイルの上位ディレクトリに当たることである。無限ループを検出した場合、 find は何が起きたかを告げる診断メッセージを標準エラーに表示し、 探索位置をディレクトリ階層上の元の位置に戻すか、終了すべきである。

GNU find はこうした要求に従っている。ディレクトリがその中に 上位ディレクトリへのハードリンクであるエントリを含んでいる場合は、 ディレクトリのリンク数が、本来ならそうなるはずの数よりも たいてい少なくなるものだ。その結果、 GNU find が時として、実際には上位ディレクトリへのハードリンクである サブディレクトリを、最適化の副作用で探索しないですますことが起こりえる。 その場合、 find は確かにそうしたディレクトリに足を踏み入れないわけだから、 「ループ検出」の診断メッセージを出さないでもよいことになっている。 これはかなり紛らわしい動作かもしれないが、 find のこの動作を本気で当てにしている人もいないことだろう。 -noleaf オプションを指定して、ディレクトリ・ツリー上の葉っぱを簡易判別する 最適化を無効にしている場合は (訳注: -noleaf 参照) 、 こうしたディレクトリ・エントリに対する検査も省略されずに行われ、 必要ならば、診断メッセージが表示されることになる。 シンボリックリンクを使うと、そういったファイルシステム上の循環は 起きないが、 -L や -follow を使用している場合は、探索中に シンボリックリンクのループに出会えば、診断メッセージが表示される。 ハードリンクを含むループの場合と同様、葉っぱを簡易判別する最適化を 使用していると、たいていの場合、シンボリックリンクに対して stat() や chdir() を呼び出すまでもないと、 find が承知していることになるので、 ループの診断は不要になることが多い。

[訳注]:
Linux や BSD 系 Unix のようにディレクトリへのハードリンクを 作成できない Unix もある。その場合は、上記のハードリンクに関する 解説は当てはまらない。

-d オプションは BSD システム各種との互換性のためにサポートされている。 だが、POSIX に準拠している -depth オプションの方を使った方がよい。

環境変数 POSIXLY_CORRECT は、判別式 -regex や -iregex の動作に影響を与えない。そうした判別式は、POSIX 標準で規定されていない からである。
環境変数

LANG
国際化関係の環境変数のうち、値が設定されていなかったり、null だったりする 変数に対して、LANG の値がデフォルトの値になる。

LC_ALL
これが空文字列以外の値に設定されていると、その値が国際化関係の 他のすべての環境変数の値よりも優先される。

LC_COLLATE
POSIX の規定によれば、この環境変数は判別式 -name で使われるパターンマッチングに影響する。 GNU find は fnmatch(3) ライブラリ関数を使用しているので、LC_COLLATE への対応は システムのライブラリ次第である。また、この変数はアクション -ok に対する応答の解釈にも影響を及ぼす。 -ok に対する応答の解釈に使用される実際のパターンは LC_MESSAGES 変数によって 選択されるのだが、パターン中に角カッコ式が現れた場合の解釈は、LC_COLLATE の 影響を受けるのである。

LC_CTYPE
この環境変数は、正規表現で使用される文字クラスの扱いに影響する。 システムの fnmatch(3) ライブラリ関数がこの変数に対応している場合は、判別式 -name の使用にともなう文字クラスの扱いにも影響を及ぼす。また、この変数は、 アクション -ok が出すプロンプトに対してユーザが応答する際、諾否の判断に使用される 正規表現の文字クラスの解釈にも関係する。さらにまた、環境変数 LC_CTYPE は、 ファイル名が表示されるとき、どの文字を表示不可能 (unprintable) と見なすかにも かかわることになる。「変わり者のファイル名」セクションを参照してほしい。

LC_MESSAGES
国際化されたメッセージのために使用されるロケールを決める。 また、環境変数 POSIXLY_CORRECT が設定されている場合は、アクション -ok が出したプロンプトに対する応答を、どう解釈するかもこの変数が決定する。

NLSPATH
国際化メッセージ・カタログを置く場所を決める。

PATH
-exec, -execdir, -ok, -okdir によって呼び出される実行ファイルを捜すために検索するディレクトリに影響する。

POSIXLY_CORRECT
-ls や -fls が使用するブロックサイズを決める。 POSIXLY_CORRECT が設定されているときは、1 ブロック 512 バイト、 設定されていないときは、1 ブロック 1024 バイトである。
また、この変数を設定すると、警告メッセージを出さないのがデフォルトになる (すなわち、 -nowarn になるわけだ)。なぜならば、POSIX の規定では、 -ok の出すプロンプトを除いて、標準エラーに出力されるメッセージはすべて 問題が起きたことを知らせるものであり、そのときの終了ステータスは 0 以外でなければならないからである。
POSIXLY_CORRECT が設定されていない場合、 +zzz が許可属性を表すシンボルとしてそれ自体有効な表現であるときを除き、 -perm +zzz は -perm /zzz とまったく同じように扱われる。 POSIXLY_CORRECT が設定されている場合は、許可属性の前に '+' や '/' を取る こうした形式は、エラーとして処理される (訳注: もちろん、+zzz がそれ自体 有効なシンボル表現であるときを除く。判別式 -perm +mode の説明を参照)。
POSIXLY_CORRECT が設定されていると、アクション -ok が出すプロンプトに対するユーザの応答を解釈する際に、 find の持つメッセージ・カタログではなく、システムのメッセージ・カタログが 参照される。
TZ
タイムゾーンに影響する。タイムゾーンは、 -printf や -fprintf の日時に関係する一部の書式指定子で使用される。

用例

find /tmp -name core -type f -print | xargs /bin/rm -f

/tmp ディレクトリ以下に core という名前のファイルを捜して、それを消去する。名前の中に改行、 シングルクォート、ダブルクォート、スペースなどを含むファイルがあるときは、 正しく動作しないことに注意すること。

find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f

/tmp ディレクトリ以下に core という名前のファイルを捜して、それを消去する。ファイル名の処理に当たっては、 ファイルやディレクトリの名前にシングルクォート、ダブルクォート、空白、 改行などが含まれていても、適切に扱われるようにする。判別式 -name を -type の前に置いているのは、すべてのファイルに対して stat(2) システムコールを行う無駄を省くためである。

find . -type f -exec file '{}' \;

カレントディレクトリ以下のあらゆるファイルに対して file コマンドを 実行する。中カッコをシングルクォートで囲んでいることに注目してほしい。 シェルスクリプトのブロック区切り記号として解釈されないようにするためである。 同様に、セミコロンもバックスラッシュを使って保護している。こちらにも シングルクォートを使用してもよい。

find / \
\( -perm -4000 -fprintf /root/suid.txt "%#m %u %p\n" \) , \
\( -size +100M -fprintf /root/big.txt "%-10s %p\n" \)

全ファイルシステムを一回だけ探索して、setuid ビットの立っている ファイルやディレクトリのリストを /root/suid.txt に、サイズの大きいファイルのリストを /root/big.txt に出力する。

find $HOME -mtime 0

ここ 24 時間の内に内容が更新されたファイルをホームディレクトリ以下で 検索する。このコマンドがそういう動作になるのは、それぞれのファイルが 最後に更新されてから現在までの経過時間が、24 で割り算され、余りは 切り捨てられるからである。そこで、ファイルが -mtime 0 にマッチするためには、過去 24 時間未満の期間内に内容が更新されて いなければならないことになる。

find /sbin /usr/sbin -executable \! -readable -print

実行可能でありながら、読み出し不可能なファイルを捜す。

find . -perm 664

ファイルの所有者とグループは読むことも書くことも可能だが、 他のユーザは読み出しのみ可能で書き込みはできないファイルを捜す。 そうした条件を満たすものの、他の許可属性ビットも立っているような (たとえば、そのファイルを実行できる人がいるような) ファイルは、 この式にマッチしない。

find . -perm -664

ファイルの所有者とグループは読むことも書くことも可能であり、 他のユーザも読むことは可能であるようなファイルを捜す。 それ以外の許可属性ビットについては (たとえば、実行許可ビット)、 立っていてもいなくてもかまわない。この条件は、たとえば、 0777 のモードを持つファイルにもマッチすることになる。

find . -perm /222

誰かが書き込めるようなファイルを捜す (書き込めるのは、ファイルの所有者でも、 グループでも、他の一般ユーザでもよい)。

find . -perm /220
find . -perm /u+w,g+w
find . -perm /u=w,g=w

上記のコマンドは三つとも同じ動作をする。最初のものは、ファイルの許可属性を 8 進数で表し、後の二つは、シンボルによる表現形式を使っている。 こうしたコマンドはどれも、ファイルの所有者かグループが 書き込み可能であるようなファイルを捜す。所有者とグループの両方が 書き込み可能な場合しか、マッチしないわけではない。どちらか片方だけでも 十分である。

find . -perm -220
find . -perm -g+w,u+w

この二つのコマンドは同じ動作をする。すなわち、ファイルの所有者と グループの両方が書き込み可能であるようなファイルを捜す。

find . -perm -444 -perm /222 ! -perm /111
find . -perm -a+r -perm /a+w ! -perm /a+x

この二つのコマンドは両方とも次のような条件のファイルを捜す。 その条件とは、誰にでも読み出すことが可能で (-perm -444 や -perm -a+r がそれにに当たる)、 書き込み許可ビットが少なくとも一つは立っているが (-perm /222 や -perm /a+w)、 誰にも実行することはできない (! -perm /111 や ! -perm /a+x) というものである。

cd /source-dir
find . -name .snapshot -prune -o \( \! -name *~ -print0 \)|
cpio -pmd0 /dest-dir

このコマンドは /source-dir の中身を /dest-dir にコピーするが、その際 .snapshot という名前のファイルやディレクトリ (及び、そのディレクトリ内のすべて) を 除外する。さらにこのコマンドは、名前の末尾に ~ が付くファイルやディレクトリも除外するが、そうしたディレクトリの 中身については除外の対象にしない。 -prune -o \( ... -print0 \) という表現はかなりよく利用される。ここで肝腎なのは、 -prune の前にある式がマッチする項目は、 find の探索の対象から -prune によって取り除かれる (訳注: pruned、枝刈りされる) ということである。 しかし、アクション -prune 自体は返り値として真を返すので、直後に続く -o によって、 探索の対象から取り除かれなかったディレクトリに対してだけ -o の右辺の評価が行われることになる (探索の対象から取り除かれた ディレクトリの中身は処理の対象にすらならないので、そうしたものは もう関係がない)。 -o の右辺の式がカッコで囲まれているのは、見やすくするためにすぎない。 アクション -print0 が行われるのは、 -prune が適用されなかった項目のみであることを強調しているわけだ。 述語間のデフォルトの結合は and であり、and 条件の結合は -o よりも強いから、カッコがあってもデフォルトの動作と同じなのだが、 カッコを使うと、何をやっているかがわかりやすくなる。

find repo/ -exec test -d {}/.svn -o -d {}/.git -o -d {}/CVS \; \
-print -prune

以下のようなプロジェクトのディレクトリとそれに関連する SCM (ソースコード管理システム) の管理用ディレクトリがある場合に、 プロジェクトのルートを効率的に検索する。

repo/project1/CVS
repo/gnu/project2/.svn
repo/gnu/project3/.svn
repo/gnu/project3/src/.svn
repo/project4/.git

この例では、 -prune を使うことによって、すでにプロジェクトのルートであることがわかった ディレクトリ以下で不必要な探索をしないですませている (たとえば、 project3/src は探索しないが、それは project3/.svn がすでに見つかって いるからである)。それでいて、同格のディレクトリ (たとえば、 project2 と project3) はきちんと見つかるようにしている。

終了ステータス

find は、すべてのファイルを問題なく処理できれば、ステータス 0 で終了する。 エラーが起きた場合の終了ステータスは、1 以上である。ここではあえて ごく大雑把な言い方をしているが、返り値が 0 以外だった場合は、 find が出した結果を正しいと思い込まない方がよいだろう。

関連項目
locate(1), locatedb(5), updatedb(1), xargs(1), chmod(1), fnmatch(3), regex(7), stat(2), lstat(2), ls(1), printf(3), strftime(3), ctime(3), Finding Files (on-line in Info, or printed).
履歴
findutils-4.2.2 以来、ファイル名のパターンに使われたシェルのメタ文字 (`*', `?', `[]' など) は、先頭の `.' にマッチする。これは、 IEEE POSIX interpretation 126 がそう要求しているからである。

-perm +MODE という書き方は findutils-4.2.21 で非推奨になった。 -perm /MODE を使用する方をお勧めする。 findutils-4.3.3 以来、 -perm /000 はどんなファイルにもマッチしないではなく、すべてのファイルにマッチする になっている。

ナノ秒まで表現するタイムスタンプは findutils-4.3.3 で実装された。

findutils-4.3.11 以来、アクション -delete は、実行に失敗すると、 find の終了ステータスを 0 以外の値に設定する。とは言え、 -delete に失敗したとき、 find が即座に終了してしまうわけではない。以前のバージョンでは、 -delete が実行に失敗しても、 find の終了ステータスは影響を受けなかった。
Feature Added in Also occurs in
-newerXY 4.3.3 BSD
-D 4.3.1
-O 4.3.1
-readable 4.3.0
-writable 4.3.0
-executable 4.3.0
-regextype 4.2.24
-exec ... + 4.2.12 POSIX
-execdir 4.2.12 BSD
-okdir 4.2.12
-samefile 4.2.11
-H 4.2.5 POSIX
-L 4.2.5 POSIX
-P 4.2.5 BSD
-delete 4.2.3
-quit 4.2.3
-d 4.2.3 BSD
-wholename 4.2.0
-iwholename 4.2.0
-ignore_readdir_race 4.2.0
-fls 4.0
-ilname 3.8
-iname 3.8
-ipath 3.8
-iregex 3.8

バグにあらず

$ find . -name *.c -print
find: paths must precede expression
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]

こうしたエラーが起きる原因は、 *.c がシェルによって展開されて、 find が実際に受け取るコマンドラインが、たとえば次のようなものに なってしまうからである。

find . -name bigram.c code.c frcode.c locate.c -print

当然ながら、こんなコマンドがうまく動くわけがない。書き方を改めて、 パターンを引用符で囲むか、ワイルドカードをエスケープするべきだ。

$ find . -name \*.c -print

バグ

POSIX 標準が find について規定している動作にはセキュリティ上の問題があるが、 それはその動作自体に内在する問題なので、修正することができない。 一例を挙げると、アクション -exec は本質的に安全ではない。だから、 -execdir の方を使うべきなのだ。 より詳しい情報については、Finding Files を参照していただきたい。

環境変数 LC_COLLATE はアクション -ok にまったく影響を及ぼさない (訳注: 環境変数 LC_COLLATE の説明では 「この変数はアクション -ok に対する応答の解釈にも影響を及ぼす」 と述べている)。

バグ報告の最善の方法は、 http://savannah.gnu.org/bugs/?group=findutils にある書式を使用することだ。そうすれば、問題解決の進行状態を 追うことができるからである。find(1) や findutils パッケージ全般についてのその他のご意見は、 bug-findutils メーリングリストにお出しになればよい。メーリングリストに参加するには、 bug-findutils-request@gnu.org 宛に E メールを送っていただきたい。

Linux なら expect でコマンドを自動化しよう

読了までの目安時間:約 117分

expect は対話的なプログラムとのやりとりを自動化するプログラムです。特定の文字列とマッチすると入力します。
対話プロンプトに自動入力できます。特定の文字列とマッチすると値を入力してくれます。
例) telnetでログインを自動化する

例) telnetでログインを自動化する
#!/usr/bin/expect --
set timeout -1
spawn telnet hogehoge.com
expect "login:"
send "hoge\r"
expect "Password:"
send "hogepasswd\r"
interact

set timeout:expectのタイムアウト値はデフォルトで10秒になっているので10秒以上かかると思われる処理の場合 set timeout -1 でタイムアウトしないようにします。
spawn:自動で実行したいコマンドを指定。
expect:指定された文字列(「”」に囲まれた文字)と標準入力のデータとを正規表現で比較し、一致するまで以降の命令を実行しません。
send:指定された文字列(「”」に囲まれた文字)を先に実行したコマンドのジョブに送信します。
interact:自動実行を終了。実行ジョブの標準入出力をキーボードと画面にします。

例) telnetでログインを自動化し、操作のログを hogehoge_log.txt に保存する

例) telnetでログインを自動化し、操作のログを hogehoge_log.txt に保存する
#!/usr/bin/expect --
set timeout -1
log_file hogehoge_log.txt
spawn telnet hoge.com
expect "login:"
send "admin\r"
expect "Password:"
send "hogepasswd\r"
interact

expect ヘルプ man より

名前
expect - 対話的なプログラムとのやりとりを自動化するプログラム, バージョン 5

書式
expect [ -dDinN ] [ -c cmds ] [ -[f|b] ] cmdfile ] [ args ]

イントロダクション
Expect は、スクリプトの指示に従って、対話的なプログラムと"会話"するプログラムである。 以下のスクリプトに示すように、 Expect には、対話プログラムからの期待されうる入力とそれに対する正しい応答を 教えておく。インタプリタは分岐処理と高度な制御構造を提供し、 対話プログラムへの指示を行なう。 さらに、必要な時にスクリプトから制御を奪って直接人間が指示を行ない、 その後、制御をスクリプトへ戻すことができる。

Expectk は Expect と Tk の混合物である。 Expect であり、かつ、 Tk's wish であるかのように振舞う。 Expect は、C あるいは C++ (つまり、Tcl 以外)から、直接使うこともできる。 libexpect(3)を参照。

"Expect"という名前は、uucpで有名になった send/expect の概念に由来する。 (kermitや他のモデム制御プログラムでも、この概念は使われている) しかし、uucp とは違って Expect は一般化されているので、想像されるどんなプログラムやタスクに対しても マクロコマンド(user-level command)として機能できる。 Expect は、同時に複数のプログラムと会話することができる。

Expect にできることの例をいくつか挙げておく:


電話代を払わずにログインできるようにコンピュータからあなたに電話を掛け直させる。

ゲーム(例えば rogue)を始める時に、最適なパラメタがもらえなかった場合 最適なパラメタがもらえるまで何度でもリスタートを行ない、その後制御を人間に移す。

fsckを走らせた時に現れる質問に、前もって決めておいた方針に従って、 "yes", "no", "手入力"を切替えて、返答する。

他のネットワークや BBS(例えばMCI Mail, CompuServe)に接続した時に 自動的にメールの取り込み、発信を行なう。

環境変数、カレントディレクトリ、その他の情報を、rlogin, telnet, tip, su,
chgrp などを行なった先へ持っていく。

これらの処理をシェルが行なえない理由はたくさんある (やってみればわかるだろう)。全部 Expect ならできる。

一般に Expect は、プログラムとユーザーのやりとりが必要なプログラムを走らせるときに 役に立つ。大事なことは、このやりとりがプログラムの性格を持っていると いうことである。 Expect は、必要ならユーザーに制御を返すこともできる(しかも、プログラムは 中断されない)。同様に、ユーザーは制御をいつでもスクリプトに返すことができる。

用法
Expect は、 cmdfile を読み込み、実行するコマンドのリストを得る。 Expect は、#! 表記をサポートする OS で、先頭行に

#!/usr/local/bin/expect -f

と書いておいて実行させることもできる。 もちろん、パスは正確に Expect のある場所を指示していなければならない。 /usr/local/bin は、一例である。

-c フラグで、スクリプトを実行する前に、実行するコマンドを指示する。 コマンドはシェルに壊されないようにクオートしておくべきである。 このオプションは何回出てきても構わない。 複数コマンドを指示した場合は、セミコロンで連結されたコマンドのように 扱われる。 コマンドは現れた順に実行される。(Expectk では、 -command と書く)

-d フラグで、デバッグ情報出力を有効にする。基本的に 内部のコマンド(例えば expect や interact) の振舞いを報告する。 このフラグは"exp_internal 1"とスクリプトの先頭に書くのと同じことだが、 さらに Expect のバージョン番号も出力される。 ( strace コマンドは、命令をトレースするのに便利である。 trace コマンドは、変数値をトレースするのに便利である。) (Expectk を使う時は、このオプションは -diag と書く。)

-D フラグで対話型デバッガを有効にする。整数値が続かなければならない。 値が 0 でないか、C が押されると、次の Tcl 処理の前でデバッガに制御が移る。 ブレークポイントにかかった時や他のデバッグ命令を実行した時も、同じである。 デバッガについての情報がもっと欲しければ、 README や下記の関連項目を読むこと。 (Expectk を使っている時は、このオプションは -Debug)

-f フラグで、コマンドを読んでくるファイルを指示する。このフラグは あってもなくても良いのだが、#! 表記と一緒に使うと 引数からプログラム名を除けるから、その場合意味がある。 (Expectk では -file)

デフォルトでは、コマンドファイルがメモリに一度に読み込まれ、そこで実行される。 一行ずつコマンドファイルを読んだ方が望ましい場合もある。例えば、 標準入力はこのように扱った方が良い。強制的にこのモードを指定するには、 -b フラグを指定する。 (Expectkでは、 -buffer) stdio のバッファリングは依然有効であるが、FIFO または stdin から読み込む場合は 問題は起こらないはずであることに注意すること。

"-"がファイル名として渡されると、標準入力からスクリプトが読み込まれる。 (本当に"-"と言うファイルが読みたければ、"./-"と書くこと)

-i フラグを指示すると、 Expect はファイルからスクリプトを読まずに対話用プロンプトを表示する。 exit コマンドか、EOF を受けるとシェルを終了する。 詳細については interpreter (下記) を参照のこと。 -i を指定した場合には、 コマンドファイルも -c も指示されなかったものとして実行される。 (Expectkでは -interactive)

-- は、オプションの終りを区切るのに用いられる(省略可能)。これは、あなたが オプションタイプの引数を Expect に解釈させないで、スクリプトにそのまま渡したい時に役に立つ。 #! 行にこれを置いて、Expect にオプションとして解釈させないようにするこ とができて便利た。

例えば、以下のように書くと(スクリプト名も含めて)オリジナルの引数は、変数 argv に残される。

#!/usr/local/bin/expect --

#!行に引数を加えると、通常の getopt(3) や execve(2) ではその引数が見えてしまう ことに注意すること。

-N フラグを用いない限り、ファイル $exp_library/expect.rc が(あれば)自動的に 実行される。 (Expectk では、 -NORC) -n フラグ (Expectk では、 -norc) を用いない限り、 続いて、ファイル ~/.expect.rc が、自動的に実行される。 環境変数 DOTDIR が定義されていれば、そこが .expect.rc のあるディレクトリ として扱われる。

この二つのrcファイルの実行より先に -c フラグで指示されたコマンドが実行される。

-v フラグを指示すると、バージョン番号を表示して終了する。 (Expectkでは、-version)

オプション args は、リストに変換されて、変数 argv に保存される。 argc は、argv のリスト長(要素の数)に設定される。

argv0 は、スクリプト名に設定される(スクリプトを使っていなければ、 バイナリの名前になる)。 例えば、以下のスクリプトを実行すると、スクリプト名と最初の引数3つを表示する:

send_user "$argv0 [lrange $argv 0 2]\n"

コマンド
Expect は、 Tcl (Tool Command Language)を使用している。 Tcl は、制御フロー(例えば if, for, break)、式評価、および、 再帰やプロシジャ定義等他のいくつかの機能を提供する。 ここで使われているのに定義がないコマンド(例えば、 set, if, exec) は、Tcl コマンドである。(tcl(3)を参照)。 Expect は、以下に記述する追加コマンドをサポートする。 記述がない場合は、そのコマンドは空文字列を返す。

コマンドはアルファベットの列なのですぐにわかると思うが、 新しいユーザーは、 spawn, send, expect, interact, が、この順で並んでいるところを読み始めた方が理解しやすいと 気がつくかも知れない。

この言語(Expect と Tcl の両方)へのイントロダクションとしては、 "Exploring Expect"という本(関連項目を参照)がベストである。 このマニュアルページはリファレンスとして書いているので、 含まれている例は非常に限られている。注意すること。

このマニュアルページで、大文字の"E"で"Expect"とあれば、それは、 Expect プログラムを指し、一方小文字の"e"で"expect"とあれば、それは、 Expect プログラムに実装されている expect コマンドを指す。注意すること。

close [-slave] [-onexec 0|1] [-i spawn_id]
カレントプロセスへのコネクションをクローズする。 ほとんどの対話型プログラムが標準入力の EOF を検出し exit する。 それゆえ、 close はそのプロセスを kill するのにも通常充分である。 -i フラグを指示すると、続く spawn_id を持つプロセスをクローズする。

expect と interact は両方とも、カレントプロセスが exit した時点を検出して、明示しなくても close を実行する。 しかし、"exec kill $pid" などのように、あなたがプロセスを kill している なら、明示的に close を呼ぶ必要がある。

-onexec フラグを指示すると、新しい spawn が起きた時またはプロセスが重ねられた時に 前の spawn を閉じるべきかどうかを指示することができる。 前の spawn id で開いたままにしておきたければ、値 0 を用いる。 0 でない整数を指示すると、新しいプロセス中では前の spawn はクローズされる (デフォルト)。

-slave フラグを指示すると、その spawn id の抱えているスレーブの spawn もクローズする。 ("spawn -pty"を参照) コネクションがクローズされると、スレーブはオープン状態であっても クローズされる。

コネクションのクローズが明示されていたか否かに全然関わりなく、 関係するカーネルプロセススロットをクリアしてしまいたければ、 wait を呼ぶこと。 close は、 wait を呼ばない。プロセスへのコネクションをクローズすると、そのプロセスが exit するという保証がないからである。 もっと知りたければ、 wait の項を参照すること。
debug [[-now] 0|1]
は、Tcl デバッガを制御する。デバッガにより、ステップ実行、ブレークポイントの 設定などが行なえる。

引数がない場合、デバッガが走っていれば 1 を、そうでなければ 0 を返す。

引数が 1 なら、デバッガが起動される。引数が 0 なら、デバッガが停止する。 引数 1 の前に -now フラグがあれば、デバッガは即座に起動される(つまり、 debug コマンドそのものの途中で)。そうでなければ、デバッガは次の Tcl コマンドから 起動される。

debug コマンドはトラップを変更しない。 -D フラグをつけて起動させた場合とはそこが違う(上記参照)。

デバッガについては、README ファイルと関連項目を参照すること。
disconnect
fork されたプロセスを端末から切り離す。バックグラウンドで動作は続く。 プロセスは可能であれば自分自身のプロセスグループを与える。 標準入出力は、/dev/null にリダイレクトされる。
以下の断片は、 disconnect を使って、バックグラウンドでスクリプトの実行を続ける。

if {[fork]!=0} exit
disconnect
. . .

以下のスクリプトは、パスワードを読んで、一時間毎にパスワードを要求する プログラムを実行する。スクリプトはパスワードを読み込んでいるので、 タイプするのは一回だけで済む。 (パスワードのエコーを避ける方法については、 stty コマンドを参照)

send_user "password?\ "
expect_user -re "(.*)\n"
for {} 1 {} {
if {[fork]!=0} {sleep 3600;continue}
disconnect
spawn priv_prog
expect Password:
send "$expect_out(1,string)\r"
. . .
exit
}

シェルの非同期実行(&)時に disconnect を用いる利点は、 Expect が disconnect の前に端末情報を保存しておいて、後で新しい pty にそのパラメタを 適用できる点にある。 & を使っていて Expect が制御を受けとって disconnect されてしまうと、端末情報を読み込むことはできない。
exit [-opts] [status]
Expect を exit させるか、そのための準備を行なう。

-onexit フラグは、続く引数を exit ハンドラとして用いる。 引数がなければ、exit ハンドラは何もしない。

-noexit フラグを指定すると Expect は、exit の準備をして OS へ制御を返す直前に停止する。 ユーザーの定義した exit ハンドラは、Expect 自身の内部ハンドラと同じように 実行される。 それ以上 Expect のコマンドが実行されるべきではない。あなたが他の Tcl Extension を Expect につけている場合にこの機能は意味がある。 Expect の exit がもう一度呼び出されると(こういう場合も起こり得る)、ハンドラは処理を 返さない。

exit する際に、全ての spawn されたプロセスへのコネクションはクローズされる。 クローズは EOF 検出によって行なわれる。 exit は、普通の exit(2) が行なう以上のことはしない。 それで、spawn されたプロセスが EOF をチェックしない場合、そのプロセスは 走り続ける。(spawn されたプロセスへ送られたシグナルを判断するといったこと には複数の条件が関わってくる。これらは、システム依存であり、典型的な動作は 各システムの exit(3) のドキュメントに記述されている。)

status (指定がないときは、0 )は、 Expect の、終了ステータスとしてシステムに返される。 exit は、スクリプトの終りに達すると、書いていなくても実行される、
exp_continue [-continue_timer]
exp_continue コマンドは expect 自身に待っていた値が来なかった時のように、expect の実行を続ける。 デフォルトでは exp_continue は時間切れタイマーをリセットする。 -continue_timer フラグはタイマーを再実行しないようにする。 (より詳細な情報は expect を参照のこと。)
exp_internal [-f file] value
value がゼロでなければ、以降のコマンドの診断情報を Expect 内部の stderr に送るようになる。 value に0を指定するとこの出力は止まる。この診断情報には、受けとった すべての文字と、現在の出力とパターンをマッチさせる全試行が 含まれる。
file オプションを指定すると、すべての通常および診断出力がそのファイルに 出力される。( value の値とは無関係に)。すでにオープンされている診断出力ファイルは、 すべてクローズされる。

-info フラグは、最後に指定された info フラグでない引数の内容を返す。
exp_open [args] [-i spawn_id]
元の spawn id に結びつけられたファイル ID を返す。 そのファイル ID は、Tcl の open コマンドでオープンした時と同様に扱える。 (spawn id は、もう使われるべきでない。 wait も実行すべきではない。)

-leaveopen フラグは、spawn id をオープンしたままにしておく。 wait が、その spawn id に対して実行されねばならない。
exp_pid [-i spawn_id]
現在の spawn されたプロセスのプロセス ID を返す。 -i フラグを指示すると、与えられた spawn id に対するプロセスの ID を返す。
exp_send
send のエイリアス。
exp_send_error
send_error のエイリアス。
exp_send_log
send_log のエイリアス。
exp_send_tty
send_tty のエイリアス。
exp_send_user
send_user のエイリアス。
exp_version [[-exit] version]
は、スクリプトが現バージョンのExpectで動くことを確かめる時に役に立つ。
引数がなければ、 Expect の現在のバージョンを返す。このバージョンはあなたのスクリプト内で 設定しても良い。あなたが最近のバージョンに入った機能を使わないの であれば、もっと前のバージョンを指定することができる。
バージョンはドットで区切られた 3 つの番号である。 最初の番号は、メジャー番号である。 違うメジャー番号の Expect 用に書いたスクリプトは、まず動かない。 exp_version は、メジャー番号がマッチしないとエラーを返す。
2 番めの番号はマイナー番号である。 使っている Expect よりマイナー番号がより大きい Expect 向けのスクリプトは、 新機能の使用未使用によるが、動かないかも知れない。 exp_version はメジャー番号がマッチしてもマイナー番号が使っている Expect のバージョンより大きいとエラーを返す。
3番めの番号は、バージョン比較には使われない。 しかし、文書の更新やプログラムの最適化が行なわれて、 Expect のディストリビューションが更新されると、番号が増えていく。 新しいマイナーバージョンが設定される度に、0 にリセットされる。
-exit フラグをつけると、バージョンが合わなかった時に Expect はエラーを表示し exit する。
expect [[-opts] pat1 body1] ... [-opts] patn [bodyn]
は、spawn されたプロセスの出力がパターンのどれかにマッチするか、 指定された時間が経過するか、enf-of-file を見つけるか、のいずれかが 成立するまでウェイトする。 最後の body が空なら、それは省略できる。
一番最後に実行された expect_before コマンドのパターンが、どのパターンより先にチェックされる。 一番最後に実行された expect_after コマンドのパターンが、どのパターンより後にチェックされる。
expect 全体への引数が 1 行に収まらなかった場合は、 引数を"ブレース"することで、各行の終りにバックスラッシュをつけるのを 避けることができる。この場合、ブレースしたにもかかわらず通常の Tcl 展開が 発生する。
もし、パターンがキーワード eof であれば、end-of-file 発見時に処理が実行される。 もし、パターンがキーワード timeout であれば、タイムアウトが発生した時に処理が実行される。 timeout キーワードが使われなかった場合、タイムアウト時にはなにもしない。 デフォルトタイムアウトは 10 秒である。設定することもできる。 例えば 30 秒と設定したければ、"set timeout 30"を実行すること。 タイムアウトさせないためには、値 -1 を設定する。 もし、パターンがキーワード default であれば、タイムアウトか end-of-file のいずれかで処理が実行される。
パターンにマッチすれば、処理は実行される。 expect は、行なった処理(関連するブレース内の処理)の結果を返す。 (パターンにマッチしなかった時は、空文字列を返す。) 複数のパターンにマッチした場合、最初にマッチしたパターンに対応する処理が 実行される。
対話型プログラムからの新しい出力が Expect に届くたびに、リストされている順に パターンとの比較が行なわれる。それゆえ、マッチすべきものがないことを 確認するために、プロンプトのように来ることがわかっているパターンを用意する ことができる。 プロンプトがない場合には、(あなたが手で打つ時に判断しているように) timeout を用いなければならない。
パターンは 3 通りに書ける。デフォルトは、Tcl の string match コマンドの書式である。(このパターンはグロブで参照される C-shell の正規表現に 似ている。) -gl フラグは、他のマッチからパターンを保護するのに使う。 "-"で始まるパターンは、この方法で保護すべきである。 ("-"で始まる文字列は将来の拡張で、オプションとして使われるかも知れないから)

例えば、以下の断片はログインの成功を監視する。 (abort はスクリプトのどこか他の場所で定義されていると仮定している。 注意すること。)

expect {
busy {puts busy\n ; exp_continue}
failed abort
"invalid password" abort
timeout abort
connected
}

4番めのパターンにはスペースが含まれているのでクオートが必要である。 アクションとパターンを分離するセパレータでないことを指示する必要がある。 (3番めと4番めの)ように同じアクションを持つリクエストも並べて書く必要が ある。これは、正規表現パターンを用いることで回避できる(下記参照)。 グロブスタイルパターンについてもっと情報が欲しければ、Tcl のマニュアルを 読むこと。
正規表現パターンは、Tcl の regexp ("regular expression"の短縮)コマンドで定義される文法に従う。 regexpパターンは、 -re フラグで始める。 前の例を、regexp で書き直すと、こうなる。:

expect {
busy {puts busy\n ; exp_continue}
-re "failed|invalid password" abort
timeout abort
connected
}

どちらのパターンのタイプも、"固定されていない"。どういう意味かというと、 文字列全体にマッチする必要はなくて、文字列のどこでもマッチすれば 良いということである。^ が先頭にマッチする。 $ が末尾にマッチする。 文字列の末尾にマッチさせなければ、spawn されたプロセスからエコーされた 文字列の途中で切り上げてレスポンスを返せることに注意すること。 正しく処理が実行されていても、出力は不自然に見える可能性がある。 それで、文字列の終りの文字を正確に記述できるなら、$ を使うことを勧める。

多くのエディタでは、^ と $ は行頭、行末に正確にマッチする。 しかし、expect は行指向ではないので、(行ではなく)データの始まりと終りに マッチする。 ("EXPECTヒント"内の、バッファリングの消化不良に関する部分を参照のこと)

-ex フラグは、"正確に(exact)"指示された文字列にマッチする。 * や ^ などの解釈は行なわれない。(ただし、通常の Tcl 展開は行なわれる)。 Exact パターンは常に固定されている。

-nocase フラグは、小文字が含まれている場合に大文字に変換してからマッチさせる。 パターンには影響しない。
出力を読んでいて、2000 バイトを超えてしまったデータは"忘れられる"。 この動作は、 match_max 関数で変更できる。 (極端に大きな値はパターンマッチの性能を低下させることに注意すること。) patlist に full_buffer を指定すると、 match_max バイト以上のデータを受けてパターンマッチしなかったときに、処理が実行される。 full_buffer キーワードの有無に関わらず、忘れられたデータは expect_out(buffer) に保存される。

patlist に、キーワード null を指定すると、ヌル文字が許可され ( remove_nulls コマンドを通して)、ヌル文字(ASCII 0)にマッチする。 glob や regexp では 0 バイトにマッチすることができない。

パターン(あるいは、eol, full_buffer)にマッチすると、マッチした部分の文字列か、 その前のマッチしなかった文字列が、変数 expect_out(buffer) に保存される。

9 個までのマッチした部分文字列は、変数 expect_out(1,string) から expect_out(9,string) に保存される。 -indices フラグをパターンの前で指定すると、マッチした部分文字列の 開始位置と終了位置が( lrange の引数として使える形で)、変数 expect_out(X,start) と expect_out(X,end) に保存される。 X は数字で 0 〜 9 まで。 0 はパターン全体がマッチした部分を指示する。 例えば、プロセスが"abcdefgh\n"を出力し、以下の形:

expect "cd"

で受けると、以下の文を実行したのと同じ結果となる。

set expect_out(0,string) cd
set expect_out(buffer) abcd

この時、"efgh\n"は出力バッファに残る。 プロセスが"abbbcabkkkka\n"を出力し、以下の形:

expect -indices -re "b(b*).*(k+)"

で受けると、以下の文を実行したのと同じ結果になる。

set expect_out(0,start) 1
set expect_out(0,end) 10
set expect_out(0,string) bbbcabkkkk
set expect_out(1,start) 2
set expect_out(1,end) 3
set expect_out(1,string) bb
set expect_out(2,start) 10
set expect_out(2,end) 10
set expect_out(2,string) k
set expect_out(buffer) abbbcabkkkk

この時、"a\n"は出力バッファに残る。 パターン"*" (と -re ".*")は、プロセスからのデータがさらに来ない限り、 出力バッファをフラッシュしない。
通常、マッチした出力は Expect の内部バッファから、切り捨てらる。 この動作は、 -notransfer フラグで抑止することができる。このフラグは、スクリプトを試している時に 役に立つ(そして、"-not"と略記しても良い)。

マッチした出力を送ってきたプロセスへの spawn id は、 expect_out(spawn_id) に保存される。

-timeout フラグは、この expect コマンドの中の timeout 時刻を timeout 変数でなく 指示された値に設定する。

デフォルトでは、パターンはカレントプロセスからの出力にマッチさせるのだが、 -i フラグを設定すると、指定された spawn_id リストに対応するプロセス群からの出力に マッチさせることができる。(次の -i での指定があるまで有効である。) spawn_id リストは、スペースで区切った spawn_id のリストか、そのような値を持つ 変数への参照でなくてはならない。

例えば、以下の例はカレントプロセスからの"connected"と $proc2 と言う名前の spawn_id からの"busy","failed","invalid password" を待ち受ける。

expect {
-i $proc2 busy {puts busy\n ; exp_continue}
-re "failed|invalid password" abort
timeout abort
connected
}

大域変数 any_spawn_id の値は、 今の expect コマンド内で -i フラグを指示した spawn_id の全てにマッチさせるために使われる。 -i フラグをパターンなしで指定すると(すなわち、別の -i が直後に続くと)、 any_spawn_id で指定された、同じ expect コマンド内の他のパターンに対して、有効になる。

-i フラグには、グローバル変数の名前を指定することもできる。その場合、 その変数は、spawn id のリストである。変数は変わるたびに読み直される。 こうすることで、コマンドが実行されている間に I/O ソースを変更すること ができる。この方法で指定される spawn id を"間接(indirect)" spawn id と呼ぶ。

break や continue などのアクションは、制御構造(すなわち、 for,proc )内で通常通りの振舞いをする。

exp_continue コマンドは、 expect ループから抜けるような状況で実行を続けさせる。
ループを書いたり、expect コマンドを繰り返すことを避ける時に便利である。 以下の例はログインを自動化するコードの断片である。 exp_continue によって、(再びプロンプトを探すための)2 つめの expect コマンドを書かなくて済んでいる。

expect {
Password: {
stty -echo
send_user "password (for $user) on $host: "
expect_user -re "(.*)\n"
send_user "\n"
send "$expect_out(1,string)\r"
stty echo
exp_continue
} incorrect {
send_user "invalid password or account\n"
exit
} timeout {
send_user "connection to $host timed out\n"
exit
} eof {
send_user \
"connection to host failed: $expect_out(buffer)"
exit
} -re $prompt
}

例えば、以下の断片は既に自動化されているユーザーガイドへのやりとりを 補助する。 この場合、端末は raw モードになる。 ユーザーが'+'を押すと変数がインクリメントされる。 "p"が押されると、プロセスへ復帰情報が送られる。 おそらくは同じように"i"が押されると、スクリプトから制御を奪い、 ユーザーからの制御が行なえる。 どの場合も exp_continue コマンドが、今の expect に、処理を行なわせた後再びパターンマッチさせている。

stty raw -echo
expect_after {
-i $user_spawn_id
"p" {send "\r\r\r"; exp_continue}
"+" {incr foo; exp_continue}
"i" {interact; exp_continue}
"quit" exit
}

デフォルトでは、 exp_continue は、タイムアウトタイマーをリセットする。 タイマを再開させるには、 exp_continue コマンドに -continue_timer フラグをつける。
expect_after [expect_args]
は、 expect_before と同様の動きをするが、 expect と expect_after の両方にマッチした場合、 expect のパターンが使用される点が異なる。 より詳しい情報は、 expect_before コマンドの項を参照のこと。
expect_background [expect_args]
は、 expect と同じ引数をとるが、その場で復帰する。 パターンは新しいデータが届くたびにチェックされる。 パターン timeout と default は、 expect_background には、意味がないし、無視される。 expect と同様に、 expect_background コマンドは expect_before や expect_after パターンを使える。

expect_background アクションが、評価される時、同じ spawn id を持つ バックグラウンドプロセスはブロックされる。 アクションが完了すると、プロセスがアンブロックされる。 バックグラウンドプロセスがブロックされている間は、 (フォアグラウンドの) expect で、同じ spawn id に接続することができる。 逆に、 expect_background がブロックされていない間は expect することができない。 特定の spawn id への expect_background は、同一 spawn id への新しい expect_background を指定すると 削除される。 パターンをつけない expect_background を指定することで、バックグラウンドでパターンマッチさせること をやめさせられる。
expect_before [expect_args]
は expect と同じ引数をとるが、その場で復帰する。 もっとも最近、同じ spawn id に対して expect_before で使われたパターン・アクションのペアが、続く expect コマンドに対して使用される。 パターンがマッチすると、 expect コマンドにマッチした時と同じように動作する。 処理は、その expect のコンテキストで行なわれる。 expect_before と expect の両方のパターンにマッチした場合、 expect_before のパターンが使われる。

パターンが指示されなかった場合、spawn id は どのパターンでもチェックされない。

-i フラグをさらに指定しない限り、 expect_before パターンは、 expect_before が実行された時に定義されたパターンにマッチする。

-info フラグは expect_before から、マッチパターンの現在の状態を復帰させる。 デフォルトでは、現在の spawn id に報告する。オプションの spawn id を 指定することもできる。例えば、

expect_before -info -i $proc

たった一つの spawn id 指定だけが許される。-indirect フラグで、直接 spawn id を抑止し、間接的な指定から得られるidを指示する。

spawn id を指示する代わりに、"-all"フラグを使って、 全ての spawn id に "-info" の報告をさせることができる。

-info フラグを使った時の出力結果は、expect_before への引数として 再利用できる。
expect_tty [expect_args]
は、 expect と似た動きをするが、文字列を /dev/tty (すなわち、ユーザーからのキー入力) から読み込む。 デフォルトでは、cooked mode で読み込まれるので、 行はリターンで終らなければならない。そうしないと expect が読めない。この動きは、 stty を使って変えられる。 (下の stty コマンドを参照)
expect_user [expect_args]
は expect と似た動きをするが、文字列を stdin(すなわち、ユーザーからのキー入力) から読み込む。 デフォルトでは、cooked mode で読み込まれるので、 行はリターンで終らなければならない。そうしないと expect が読めない。この動きは、 stty を使って変えられる。 (下の stty コマンドを参照)
fork
は、新しいプロセスを作る。この新しいプロセスは、現在の Expect プロセスの正確なコピーである。 成功すると fork は 新しい(子)プロセスに 0 を返し、親プロセスに 子プロセスのプロセスIDを 返す。 失敗する(スワップ、メモリなどのリソース不足か?)と、 fork は、親プロセスに -1 を返す。新しい子プロセスは作成されない。
フォークされたプロセスは、 exit コマンドで ext できる。元のプロセスと同様である。 フォークされたプロセスはログファイルを作っても良い。多くのプロセスで デバッグもログもできなければ、結果、混乱するだけである。
pty のインプリメンテーションの中には、複数の読み手と書き手が一瞬でもあれば、 混乱するものがある。それで、プロセスを spawn する前には fork しておくのが一番安全である。
interact [string1 body1] ... [stringn [bodyn]]
は、現プロセスの制御をユーザーに渡す。結果、 現プロセスに送られたキーストロークと現プロセスの標準出力と標準エラー出力が 復帰する。
string と body の組が、引数として指示できる。(デフォルトでは、 文字列は現プロセスには送られない) 最後の body がないと、 interpreter コマンドが実行される。
interact コマンド全体への引数が一行に収まらない場合、"brace"することで各行の終りに バックスラッシュを入れるのを避けることができる。この場合、Tcl の展開は ブレースしてあっても起こる。
例えば、以下のコマンドは続く string body の組と対話する。 : ^Z が押されると Expect はサスペンドする。 ( -reset フラグは、端末モードを復旧させる。) ^A が押されると、ユーザーには"you typed a control-A"が返る。
$ が押されると、ユーザーには日付が返る。 ^C が押されると、 Expect は、exit する。 "foo"が入力されると、ユーザーに "bar" が返る。 ~~ が押されると、 Expect インタプリタは、対話モードになる。

set CTRLZ \032
interact {
-reset $CTRLZ {exec kill -STOP [pid]}
\001 {send_user "you typed a control-A\n";
send "\001"
}
$ {send_user "The date is [exec date]."}
\003 exit
foo {send_user "bar"}
~~
}

string と body の組で、string が引数として並べられた順に比較される。 部分的にマッチした文字列は、残りが到着するまで送られて来ない。 何文字かさらに打ち込まれて、マッチが可能になると、今のマッチを判断する ためにだけ使われて他のマッチを始めることはしない。それゆえ、部分的に マッチしている文字列のマッチが完了するのは遅れることがある。 部分的にはマッチするが最終的にはマッチしない文字列の場合などである。
デフォルトでは、ワイルドカードを含まないマッチは、exactとなる。 ( expect コマンドがデフォルトでグロブスタイルのパターンを用いるのとは対照的に。) -ex フラグは、パターンをプロテクトするのに使える。 interact フラグがそうするように。 パターンが"-"で始まる場合、この方法で保護できる。 ("-"で始まる文字列は全て将来のオプションとして予約されている。)

-re フラグは、正規表現スタイルのパターンとして文字列を解釈する。 この場合、マッチした部分文字列は interact_out に保存される。 expect が、その出力を変数 expect_out に保存するのと似たようなものである。 -indices フラグも同じようにサポートされる。

パターン eof は、end-of-file にマッチした場合にアクションを実行する。 複数に分かれた eof パターンには -output フラグが続いても良い。その場合、出力が書かれている間に eof が検出されると アクションを実行する。 eof のデフォルトアクションは"return"である。 それで、 interact は、EOF を見つけると復帰する。

timeout パターンは、(秒で表現された)タイムアウトにマッチし、アクションを実行する。 timeout パターンは、最後に指示されたプロセスに適用される。タイムアウトには デフォルトの値はない。(expect内で使われる)特殊な変数"timeout"は、 このタイムアウトと関係しない。

例えば、以下の記述は一時間以上タイプしなかったユーザーを自動的にログアウト させる。その前にシステムから頻繁にメッセージを受けとる:

interact -input $user_spawn_id timeout 3600 return -output \
$spawn_id

パターン null と nulls は、( remove_nulls コマンドを通して)、アスキーの 0 にマッチした場合にアクションを実行する。 glob や regexp で 0 バイトにマッチさせることはできない。

このパターンの前に -iwrite フラグをつけると、 変数 interact_out(spawn_id) にパターン(あるいはeof)にマッチした spawn_id が設定される。

break や continue といったアクションは、制御構造 (すなわち、 for や proc )の中で、通常通りに動く。 しかし、 return は、interact を呼出元に復帰させる。一方、 inter_return は、 interact をその呼びだし元内に復帰させる。例えば、"proc foo" は interact を呼ぶ。interact が、さらに、 inter_return を実行すると proc foo が復帰する。(これは、 interact が、 interpreter を呼んで return とタイプすると、そのinteractは継続するが、 inter_return すると、その呼出元に復帰してしまうということである。)
interact の間 raw モードが使用されるので、全ての文字が現プロセスに渡される。 現プロセスがジョブコントロールシグナルを捕まえなければ、 ストップシグナル(デフォルト^Z)で停止する。再スタートするには、 制御シグナルを送る。("kill -CONT "とか打って)。 本当に SIGSTOP をプロセスに送りたいなら、csh を spawn してその上で プロセスを起動すること。 そうでなくて、 Expect そのものに SIGSTOP を送りたいなら、インタプリタを呼び出して (普通はエスケープ文字)、その後 ^Z を打つこと。
string bodyのペアは、インタプリタに入ってコマンドを対話的に実行するのを 避けることを簡単に書くのに使われる。 前の端末モードが、その body を実行する間使用される。
実行速度を上げるには、デフォルトでアクションが raw モードで動くように する。 -reset フラグは、端末の持っているモードをリセットする。そうしなければ、 その前に行なった interact コマンドの端末モード(cooked モードとか)が保持される。 モードが切り替わった時に、それまで打っていた文字が消えてしまうことが あるので注意すること。(システムによっては、そういう不幸な仕様をした 端末ドライバが動いている。) -reset を使うのは、アクションが cooked モードでしか動かない場合だけである。
-echo フラグは、一文字づつパターンにマッチする文字を返す。これは、 ユーザーが打つ文字に部分的にマッチしなければならない場合に有効である。
パターンはエコーされたがマッチには失敗した場合、文字列は、spawn された プロセスに送られる。それから、spawn されたプロセスが文字列を表示し、 ユーザーは文字列を二度見る。 -echo は、ユーザーがパターンを完成させてくれそうもない場合にだけ有効であろう。 例えば、以下は rftp(リカーシブ ftp スクリプト)からの抜粋だが、ユーザーが ~g, ~p, ~l を打つとカレントディレクトリから再帰的(リカーシブ)に get, put, list する。通常の ftp ではこれらの操作ができない。間違って ~ を 打つか、~ の後を間違えた場合、その文字列を無視するようになっている。

interact {
-echo ~g {getcurdirectory 1}
-echo ~l {getcurdirectory 0}
-echo ~p {putcurdirectory}
}

-nobuffer フラグは、文字が読まれる度に、その文字をマッチへ送る。

このフラグは、パターンをエコーバックする時に有効である。 例えば、以下は誰かが(ヘイズモデムを)ダイアルするのを監視するのに 使われる。"atd"が見える度にスクリプトが残りのラインをログする。

proc lognumber {} {
interact -nobuffer -re "(.*)\r" return
puts $log "[exec date]: dialed $interact_out(1,string)"
}

interact -nobuffer "atd" lognumber

interact の間、前に使った log_user は無視される。特に、 interact は、その出力を記録される(標準出力に送られる)。 というのは、ユーザーはエコーバックのない状態でキーを打ちたくはない だろうと考えるからである。
-o フラグは、現プロセスの出力に key body ペアの key を結びつける。 こんな場合に便利である。例えば、telnet セッション中に望まない文字を 送ってくるホストを扱う場合である。
デフォルトでは、 interact は、ユーザーが Expect プロセス自身の標準入力に書き込み、標準出力を見ていると思っている。 -u フラグ("user"のu)は interact に、引数で付けられた名前(spawned id である)のプロセスをユーザーとして 扱う。
これにより、変なループなしに2つの無関係なプロセスを結合させることが できる。デバッグする時の助けとして、Expect は常に診断結果を stderr へ送る。(ある種のログとデバッグ情報は stdout に送られる)。 同じ理由で、 interpreter コマンドは、stdin からデータを読む。
例えば、以下の断片はログインプロセスを作る。そして、(表示されない) ユーザーにダイアルし、両方の接続を行なう。 もちろん、loginをどんなプロセスに変えても良い。例えば、シェルなら、ア カウントとパスワードを与えなくてもユーザーが起動できる。

spawn login
set login $spawn_id
spawn tip modem
# dial back out to user
# connect user to login
interact -u $login

複数のプロセスへの出力を行なうため、 -output フラグを前につけた各 spawn id のセットがリストされる。 出力 spawn id の組への入力は、 -input フラグによって決定される。 ( -input と -output フラグは両方とも expect コマンドの -i フラグと同じ書式である。( interact 内の any_spawn_id は意味がない点を除く。) 以下のフラグと文字列(あるいはパターン)は全て、別の -input フラグが現れるまで この入力を適用する。 -input が現れなかった場合、 -output は "-input $user_spawn_id -output" を行なう。 ( -input を持たないパターンも同様である。) -input が一つだけ指示されると、$user_spawn_id はその値で置き換わる。 二つめの -input が指示されると、$spawn_id が置き換わる。 以降の -input フラグも指定できる。

2つの入力プロセスはデフォルトで $spawn_id と $user_spawn_id に出力される。 もし、 -input フラグが -output フラグなしで指定された場合、プロセスからの文字は捨てられる。

-i フラグは、現在の spawn_id を書き換える。 ただし、 -input または -output フラグが使われていない場合である。-i フラグは -o フラグを含む。

間接 spawn id を使って会話しているプロセスを切替えることが可能である。 (間接 spawn id は、expect コマンドの項で説明した) 間接 spawn id は、-i, -u, -input, -output フラグで指定できる。
interpreter [args]
は、ユーザーに Expect と Tcl コマンドのためのプロンプトを表示する。 各コマンドの結果が表示される。
break や continue は制御構造(すなわち、 for proc )で、通常通りに動く。 しかし、 return は、呼出元への復帰を行なうのに対し、 inter_return は interpreter を、呼出元を復帰させる。たとえば、 "proc foo" は、 interpreter を呼び、 inter_return を実行し proc foo が復帰する。 他のコマンドは interpreter に新しいコマンドのためのプロンプトを表示し続ける。
デフォルトでは、プロンプトは 2 つの整数を含んでいる。 最初の数は評価スタックの深さ(つまり、何回 Tcl_Eval が呼ばれたか) 2番めの数は、Tcl ヒストリ識別番号である。プロンプトは "prompt1"と呼ばれるプロシジャを定義することで設定できる。 このプロシジャの帰り値が次のプロンプトとなる。 記述に開きクオート、括弧、ブレース、ブラケットがあると、次の行には 第 2 プロンプトが現れる(デフォルトは "+> ")。第 2 プロンプトは "prompt2"と呼ばれるプロシジャを定義することで設定できる。
interpreter の間は、呼出元が raw モードであったとしても、cooked モードが使われる。
stdin が閉じられると、 interpreter は -eof フラグが使われていない限り復帰する。 使われている場合は引き続く引数を実行する。
log_file [args] [[-a] file]
ファイル名が与えられると、 log_file は、(現時点からの)セッションのログをそのファイルに採取する。 引数がなければ、 log_file は記録をやめる。使っていたログファイルはクローズされる。

ファイル名の代わりに、Tcl ファイル識別子を指定すると、 -open や -leaveopen フラグが使える。 spawn コマンドと同様だ(より詳しくは、 spawn を参照)

-a フラグは、 log_user コマンドによって抑止されたログに出力を強制するものである。

デフォルトでは、 log_file コマンドは古い記録を消して書き直したりせずに 追記 する。 ログオフや複数のログを書く時に都合が良いように。 ファイルを消して書き直す時は -noappend フラグを使う。

-info フラグは、最後にログした内容を返す(最後が-infoフラグ付きだったら、 その前の内容)。
log_user -info|0|1
デフォルトでは、send/expect ダイアログは標準出力にロギングされる。 (開いていればログファイルにもロギングされる。) "log_user 0"とすると、標準出力へのロギングが抑止される。 "log_user 1"とすると、復旧する。ログファイルへの記録については 変更はない。

-info フラグは、最後にログした内容を返す(最後が -info フラグ付きだったら、 その前の内容)。
match_max [-d] [-i spawn_id] [size]
は、バッファサイズを(バイト単位で)定義する。このバッファは、 expect の内部で使われる。 引数 size がないと、現在のサイズを復帰する。
-d フラグを指示すると、デフォルトサイズが設定される。(初期状態の デフォルト値は 2000。) -i フラグを指示すると、名前つき spawn id に対してサイズが設定される。 指定しなければ、カレントプロセスに対して設定される。
overlay [-# spawn_id] [-# spawn_id] [...] program [args]
は、 program args を現在の Expect プログラム上で実行する。現在の Expect プログラムは終了する。 ただのハイフンが引数に指定されると、コマンド名の前にハイフンをつけて ログインシェルとして扱う。 全てのクローズ中の spawn_id は、引数に使われた文字列を待つ。
Spawn_id は、新しいプログラムに継承させるためのファイル ID に マップされる。例えば、以下の行はチェスを行ない、chess master という現プロセスに制御させる。

overlay -0 $spawn_id -1 $spawn_id -2 $spawn_id chess

これは、 "interact -u" とするよりも効果的である。しかし、 Expect プロセスが制御していないのでプログラム能力が犠牲となる。
制御されない端末ができてしまうことに注意すること。それで、 disconnect するか標準入力をリマップするとジョブ制御プログラム (シェル、ログインなど)が正しく機能しない。
parity [-d] [-i spawn_id] [value]
は、spawn idの出力からパリティを保持するか取り除くかを設定する。 value が 0 であれば、パリティは取り除かれる。 それ以外の場合、取り除かれない。 value が指定されない場合、現在の値が復帰する。
-d フラグは、パリティのデフォルト値を設定する。(イニシャル時のデフォルト値は 1 である。すなわち、パリティが取り除かれる。) -i フラグを指示すると、パリティの値が引数の名前つきの spawn id に対して 設定される。引数がなければ現在のプロセスに対して設定される。
remove_nulls [-d] [-i spawn_id] [value]
は、前にパターンマッチしたあるいは expect_out か interact_out に保存されている spawn されたプロセスの出力からヌルを保持するか取り除くかを 設定する。 value が 1 なら、ヌルは取り除かれる。もし、 value が 0 なら、ヌルは取り除かれる。 value がなければ、現在の値が復帰する。
-d フラグは、デフォルト値を設定する。(イニシャルのデフォルト値は、 1 である。それゆえ、ヌルは取り除かれる。) -i フラグは、名前つきの spawn id に対して値を設定する。なければ、 現プロセスに対して設定する。

ヌルを取り除くかどうかによらず、 Expect は、ログと標準出力にはヌルが記録される。
send [-flags] string
string を現プロセスに送る。 例えば、以下のコマンド:

send "hello world\r"

は、文字 h e l l o w o r l d を現在のプロセスに 送る。 (Tcl は、printf に似たコマンド ( format と呼ばれる )を持っていて、複雑な文字列を組み立てることができる。)
文字は直ちに送られる。ただし、入力にラインバッファのあるプログラムでは、 リターンコードが送られるまで文字が読まれない。リターンコードは、 "\r"と表記する。

-- フラグは、続く引数をフラグと解釈せず文字列として解釈される。 全体としてフラグに見えなくても"--"が前についた文字列はフラグとして 扱われてしまう。このフラグは処理されていない文字列がフラグとして 扱われるのを防ぐ。 ("-"で始まる文字は全て将来のオプションとして予約されている。)

-i フラグは、名前つきの spawn_id に文字列を送ることを宣言する。 その spawn_id が user_spawn_id であれば、端末はraw モードに入り、文字列中の改行が復帰改行シーケンスに 変換される。それで、外からは 端末が cooked モードとなっているように 見える。 -raw フラグは、この変換を抑止する。

-null フラグは、ヌル文字を送る(0 バイト)。デフォルトでは、ヌル文字を 1つ送る。 -null に続く整数はヌル文字をいくつ送るかを指示する。

-break フラグは、ブレーク状態を作る。spawn id が"spawn -open"で指示した tty デバイスを参照する場合のみ意味がある。tip などのプロセスを spawn する場合、tip の都合で ブレーク状態を作るべきである。

-s フラグは、出力を強制的に"遅く"する。結果、コンピュータが打ち込んでいる バッファに人間が打ち込んでしまう状況を避けることができる。この出力は 変数"send_slow"の値で制御される。この変数は二つの要素を持つリストである。 最初の要素は、アトミックに送るバイト数である。2 番めの要素はアトミックに送る 間隔(秒)である。例えば、 "set send_slow {10 .001}" は "send -s" に 10 文字送る毎に1ミリ秒待つように指示する。

-h フラグは、人間の実際の入力に似せて send を行なう。(アルゴリズムは、 Weibull distribution に基づいていて、この特定のアプリケーション Expect? に 合わせるための修正が行なわれている。) この出力は変数"send_human"の値で制御されていて、この変数は 5 つの要素から なるリストで最初の 2 つの要素は文字間の平均インターバル時間(秒)である。 1 つめがデフォルト値で、2 つめが(通常発生する微妙な待ち時間を表現する) 単語の終りの値である。3 つめの要素は変動率である。 可能な値は 0 から 無限大である。最後の 2 つのパラメタは、それぞれ、 インターバル時間の最小値と最大値である。この 2 つの値は最後に使われて、 最終時刻をクリップする。この 2 値が違うと究極の平均は与えられた平均とは、 全く違ったものになる。

例として、続くコマンドが一定の速度で速く打つタイピストを エミュレートする:
set send_human {.1 .3 1 .05 2}
send -h "I'm hungry. Let's do lunch."

ハングさせてしまった後は、以下のようにした方が良いだろう。:
set send_human {.4 .4 .2 .5 100}
send -h "Goodd party lash night!"

send にエラーや修正を埋め込んであっても、 エラーはシミュレートされない点に注意すること。

ブレークを送るためや、ゆっくりした出力を行なったり、人間が出力したように 見せかけるためにヌル文字を送るフラグは相互排他される。 最後に指定されたものだけが使われる。それ以上は、 string の引数が、ヌル文字あるいはブレークを送るフラグとして指定できる。

最初の send より前に expect を置いた方が良い。 expect は、プロセスが始まるのを待てるが、 send は待てない。 特に、最初の send は、プロセスが走り始める前に完了する。あなたのデータが無視される 危険がある。 最初にプロンプトを表示しないような対話的なプログラムでは、 次のように send の前にディレイをつけることができる:

# どのように破るかのヒントをハッカーに与えてしまわないように、
# このシステムでは外部のパスワードに対するプロンプトを提供しない。
# exec が完了するのを 5 秒待て。
spawn telnet very.secure.gov
sleep 5
send password\r

exp_send は send のエイリアスである。あなたが Expectk か、Tk 環境で動く Expect の他の変種を 使っている場合、 send は、全く異なった目的のために使われている。 exp_send が、両環境の間での互換性のために提供されている。 似たようなエイリアスが他の Expect の他の send コマンドのために提供されている。
send_error [-flags] string
send と似たようなもので、現プロセスでなく stderr に出力される。
send_log [--] string
send と似たようなもので、ログファイルだけに string を送る。( log_file を参照。) 引数はログファイルが open されていなければ無視される。
send_tty [-flags] string
send と似たようなもので、現プロセスでなく /dev/tty へ出力を送る。
send_user [-flags] string
send と似たようなもので、現プロセスでなく標準出力へ出力を送る。
sleep seconds
は、与えられた数字の秒数だけスクリプトがスリープする。 seconds は、10進数だけが許される。 (Expectk を使っている場合、Tkのイベントと)割り込みは、Expectが スリープしている間も処理される。
spawn [args] program [args]
program args を走らせる新しいプロセスを生成する。その標準入力と標準出力は Expect に結びつけられる。それで、他の Expect コマンドで読んだり書いたりできる。 接続は close によって、あるいは、プロセスそのものがファイル ID の いずれかをクローズした場合、破壊される。
プロセスは spawn によって始められる。変数 spawn_id には、そのプロセスへの参照を行なう識別子が設定される。 spawn_id によって記述されるプロセスは current process が考慮される。 spawn_id は、読んでも書いても良く、効果的なジョブ制御を提供する。
user_spawn_id はユーザーを参照する識別子の入ったグローバル変数である。 例えば、 spawn_id が、この値に設定された場合、 expect は、 expect_user のような動きをする。

error_spawn_id は、標準エラー出力を参照する識別子の入ったグローバル変数である。 例えば、 spawn_id が、この値に設定された場合、 send は、 send_error のような動きをする。
tty_spawn_id は、/dev/tty を参照する識別子の入ったグローバル変数である。 /dev/tty が存在しない(cron, at, バッチスクリプトの中)場合、 tty_spawn_id は定義されない。以下のように確認することができる。:

if {[info vars tty_spawn_id]} {
# /dev/tty exists
} else {
# /dev/tty doesn't exist
# probably in cron, batch, or at script
}

spawn UNIX プロセス ID を復帰する。spawn されたプロセスがない場合、0 が 復帰する。変数 spawn_out(slave,name) は pty スレーブデバイスの名前に設定される。
デフォルトでは、 spawn はコマンド名と引数をエコーする。 -noecho フラグで spawn がこうするのを止められる。
-console フラグは、コンソールへの出力を起こし、spawn されたプロセスへの リダイレクトされる。この機能は未サポートのシステムがある。

内部的に、 spawn は pty を使い、ユーザーの tty と同じように初期化される。これは、かなり 初期化してしまうので全ての設定が (stty(1)によると) "正常(sane)" になる。 変数 stty_init が定義されていると、stty の引数の形式を解釈できるので、より詳細な設定を 行なえる。例えば、 "set stty_init raw" は、以降 spawn されたプロセスの端末を raw モードで開始する。 -nottycopy は、ユーザーの tty に基づいた初期化を飛ばす。 -nottyinit は、"正常な"初期化を飛ばす。
普通、 spawn は、実行するのにわずかの時間しかかからない。spawn に時間をかけたいので あれば、おそらく割り込まれた pty に遭遇するだろう。たくさんのテストが 間違ったプロセスに掛かり合うことを避けることができる。 (割り込まれた pty につき、10 秒かかる。) -d オプションをつけて Expect を走らせると、 Expect がおかしな状態のたくさんの pty に遭遇しているかどうかが表示される。 これらの pty がつながっているためにプロセスを殺せない場合、リブートするしか 頼れる復旧手段はない。

exec(2)が失敗して program が spawn に成功しなかった場合 (例えば、 program がなかった場合など)、エラーメッセージが次の interact か expect コマンドで復帰する。つまり。 program が、出力としてエラーメッセージを出しているように見せる。 この動作は、 spawn の実装の自然な帰結である。内部で、spawn がフォークされ、その後、 spawn されたプロセスがオリジナルの Expect プロセスとその spawn_id で会話を行なう。

-open フラグは、次の引数を Tcl ファイル識別子として解釈する(つまり、 open を行なって復帰する。 ) spawn id は、spawn された id として使われる。(ファイル識別子は、 もう使うべきではない。) これにより、 pty を除く、raw デバイス、ファイル、パイプラインを使うことができる。 0 が返ってくるのは、関連するプロセスがなかった時である。 spawn されたプロセスへの接続がクローズされると、Tcl ファイル識別子も クローズされる。 -leaveopen フラグは、 -open と似た動きをするが、 spawn id をクローズした後もファイル識別子を開いたままにする点が違う。

-pty フラグは、 pty をオープンするがプロセスをspawnしない。0 が復帰するのは、 関連するプロセスがない場合である。spawn_id は、通常通り設定される。

変数 spawn_out(slave,fd) には、pty スレーブとつながっているファイル識別子が設定される。 "close -slave" で close できる。

-ignore フラグは、spawn されたプロセス中で無視されるシグナルの名前を指示する。 なければ、シグナルはデフォルトの振舞いをする。シグナルの名前は trap コマンドで使う名前と同じである。各シグナルを分離するのにフラグが 必要な点を除いては。
strace level
は、以降の命令を実行する前に表示を行なう。 (Tcl の trace は、変数のトレースを行なう。) level は、トレースへの呼び出しスタックの深さを示す。 例えば、 以下のコマンドは Expect 最初の 4 レベルの呼び出しをトレースする。 それ以上の深さはトレースしない。

expect -c "strace 4" script.exp

-info フラグを指定すると、strace は最後の info でない指定の内容を復帰する。
stty args
は端末モードを変更する。外部の stty コマンドと似たようなものである。

デフォルトでは、制御している端末がアクセスされる。他の端末は、 "< /dev/tty..." を追加することでアクセスできる。(引数を一つの引数に まとめるべきではない。) ステータス要求はコマンドの結果としてステータスを復帰する。 ステータスが要求されずに制御している端末にアクセスする場合、直前の raw と echo の状態を返す。 例えば、引数 raw か -cooked は、端末を raw モードに設定する。 引数 -raw か cooked は、端末を cooked モードに設定する。 引数 echo か -echo は、端末をそれぞれ echo あるいは noecho モードに設定する。 以下の例は、一時的なエコー禁止をどうやっておこなうかを示す。 これは、他の自動スクリプトで、その中にパスワードが埋め込まれるのを 防ぐことに使われる。(もっと議論したければ、下の EXPECT ヒントに ある。) stty -echo send_user "Password: " expect_user -re "(.*)\n" set password $expect_out(1,string) stty echo system args は、 args を、sh(1)に入力する。端末からコマンドを叩くのとちょうど同じである。 Expect は、シェルが終るのを待つ。sh からの復帰値は、 exec がその復帰値を扱うのと同じに扱われる。 exec が、スクリプトに標準入出力をリダイレクトするのと対照的に、 対照的に system は、リダイレクションを行なわない。(他に文字列そのものでリダイレクトを 指示しない限り。) それで、/dev/tty と直接話さなければならないプログラムを 使うことができる。同じ理由で、 system の結果は、ログに記録されない。 timestamp [args] は、タイムスタンプを復帰する。 引数がない場合、復帰するまでの秒数が返る。 -format フラグは、文字列が続くが、その文字列に POSIX の strftime のルールに従って置換がかかる。 例えば、 %a は曜日(すなわち、Sat)とか。他は以下の通りである。: %a 略記された曜日の名前 %A 略されない曜日の名前 %b 略記された月の名前 %B 略されない月の名前 %c 次の形式で書かれた時刻: Wed Oct 6 11:45:56 1993 %d 日 (01-31) %H 時 (00-23) %I 時 (01-12) %j 日 (001-366) %m 月 (01-12) %M 分 (00-59) %p am または pm %S 秒 (00-61) %u 日 (1-7, 月曜日が週の最初の日) %U 週 (00-53, 最初の日曜日が第1週の最初の日) %V 週 (01-53, ISO 8601 スタイル) %w 日 (0-6) %W 週 (00-53, 最初の月曜日が第1週の最初の日) %x date-time as in: Wed Oct 6 1993 %X time as in: 23:59:59 %y year (00-99) %Y year as in: 1993 %Z timezone (or nothing if not determinable) %% a bare percent sign この他の % 指定は定義されていない。他の文字は変更されない。 C ロカールだけがサポートされる。 -seconds フラグは、 タイムスタンプを秒で表す。 -gmt GMT タイムゾーンで出力する。デフォルトはローカルタイムゾーンである。 trap [[command] signals] を実行すると、以降指定された signal を受けとると指定された command を実行する。 このコマンドは、グローバルスコープで実行される。 もし、 command が指定されなければ、シグナルアクションが復帰する。 command が、文字列 SIG_IGN であれば、シグナルが無視される。 command が、文字列 SIG_DFL であれば、シグナルはデフォルトの動きをする。 signals は、シグナルが1つでも複数のシグナルのリストでも良い。シグナルは、 数字とsignal(3)に記述されている文字列のどちらで指定しても良い。 プレフィクスの"SIG"は、省略しても良い。 引数がなければ(または、引数 -number であれば)、 trap は、trapコマンドで横取りされているシグナル番号を復帰する。 -code フラグはコマンドコードを返す。Tcl がコマンドを動かし始めた時に 帰そうとしたコードである。 -interp フラグは、trap が宣言された時でなくコマンドが開始された時にインタプリタに コマンドを評価させる。 -name フラグは、 trap コマンドに trap のかかっているシグナル名を帰す。 -max フラグは、 trap コマンドに設定できる最も大きなシグナル番号を帰す。 例えば、"trap {send_user "Ouch!"} SIGINT" は、 ユーザーが ^C を押す度に "Ouch!" を表示する。 デフォルトでは、SIGINT(通常 ^C を押すと発生する)や SIGTERM は、Expect を exit させてしまう。これは、Expect が起動時に 実行する以下の trap によって起こっている。 trap exit {SIGINT SIGTERM} -Dフラグを使ってデバッガを起動するなら、SIGINT が再定義されてから対話型 デバッガが起動される。これは以下の trap によって起こる。 trap {exp_debug 1} SIGINT デバッガのトラップは、環境変数 EXPECT_DEBUG_INIT を設定して、新しく trap を起動することで変更できる。 もちろん、スクリプトにtrapコマンドを足すだけで例のトラップは両方とも 上書きできる。特に、自作の "trap exit SIGINT" があるなら、これは デバッガのトラップを上書きしてしまう。ユーザーにデバッガを全く 触らせないようにするのに、便利である。 SIGINT のトラップを独自に定義したいけれど、デバッガにも同時に割り込んで もらいたいのであれば、こう書く。: if ![exp_debug] {trap mystuff SIGINT} 代わりに、別のシグナルを使ってデバッガに割り込みをかけることができる。 trap は、SIGALRM のアクションを上書きしない。 Expect が内部で使用しない。 disconnect コマンドは、SIGALRMを SIG_IGN (ignore)に設定する。 後から発行される spawn コマンドを実行している間、SIGALRM は ディスエーブル中であれば再度イネーブルにできる。 もっと情報が欲しい場合、signal(3) を参照すること。 wait [args] は、spawn されたプロセス(あるいは、名前つきのプロセスがなければ現在のプロセス) が終了するのを待つ。 wait は、通常 4 つの整数のリストを帰す。 最初の整数は、終了を待ち構えているプロセスの pid である。 2 つめの整数は、関連する spawn id である。 3 つめの整数は、オペレーティングシステムエラーがあれば -1、 そうでなければ、0 である。 3 つめの整数が 0 であれば、4 つめの整数はspawnされたプロセスからのリターン コードである。3 つめの整数が -1 であれば、4 つめの整数はオペレーティングシステム によって設定された errno の値である。グローバル変数 errorCode も設定される。 追加の要素が wait の復帰値に加わっても構わない。オプションの5つめの要素は、情報クラスの 識別子である。今のところ、この要素の唯一可能な値は CHILDKILLED で、 その場合、次の二つの値が C スタイルのシグナル名と短い文書による記述である。 -i フラグによって、wait を行なう名前付き spawn_id(プロセス ID ではなく)を 指定する。SIGCHLD ハンドラの内部では、spawn ID -1 を指定することで、 spawn されたプロセスのいずれかを wait できる。 -nowait フラグを指定すると、wait が成功の復帰値で即時復帰する。 (あとで)そのプロセスが exit すると、自動的に後始末が行なわれ、明示的に wait する必要がない。 wait コマンドは、引数に "-i -1" を指定することによって、 fork したプロセスを待つためにも使われる。 spawn したプロセスに用いられる場合と異なり、 このコマンドはいつでも実行できる。 どのプロセスを待つかを制御することは出来ないが、 返り値はプロセス ID としてチェックできる。 ライブラリ Expect は、スクリプトのための二つのビルトインライブラリを自動的に理解する。 それらは変数 exp_library と変数 exp_exec_library に設定されたディレクトリ名と して定義される。これらのディレクトリには、他のスクリプトによって使える ユーティリティファイルが入っている。 exp_library には、アーキテクチャに依存しないファイルが格納される。 exp_exec_library には、アーキテクチャに依存するファイルが格納される。 あなたのシステムによっては、両方のディレクトリが空という場合もあり得る。 ファイル $exp_exec_library/cat-buffers の存在は、あなたのシステムの /bin/cat がデフォルトでバッファリングされているかどうかに左右される。 整形印刷 Expect スクリプトをきれいに印刷するための vgrind の定義がある。 Expect ディストリビューションと一緒に配布されている vgrind 定義が正しく インストールされていると仮定して、こうすれば使える。 vgrind -lexpect file 例 マニュアルページによる記述では、あらゆるものをどう組み合わせるのかと いうことが明白ではない。私としては、 Expect ディストリビューションの example ディレクトリにある例を読んで試してみて欲しいと思う。 いくつかは本物のプログラムである。それ以外は特定のテクニックの単純な解説、 あと、もちろん、単なるクイックハックが少しある。 INSTALL ファイルにはこれらのプログラムの簡単な梗概が書かれている。 Expect の論文も役に立つ(関連項目参照)。いくつかは、初期バージョンの Expect の 文法を使っているが、それとともにある根本的な考えは、なお有効であり、 このマニュアルページより詳細に書かれている。 警告 拡張は Expect のコマンド名と衝突するかもしれない。例えば、 send は、Tk では全く別の目的で定義されている。 そういう理由で、ほとんどの Expect コマンドは、"exp_XXXX" という 別の記法(エイリアス)もサポートする。 "exp", "inter", "spawn", "timeout" で始まるコマンドと変数は、 エイリアスを持たない。 この環境間の互換性が必要であれば、拡張されたコマンド名を用いること。 Expect は、かなり自由なスコープを持っている。特に、 Expect プログラムで指定したコマンドにより読み込ませる変数は、そのローカルスコープ 内でまず探索され、見つからなければ、グローバルスコープで探索される。 例えば、こうすることで expect を使う全てのプロシジャに "global timeout" を書く必要が なくなる。 逆に、プロシジャ内に書かれた変数は全てローカルスコープ内に設定される。 ("global"コマンドを指定しない限りは)。この動作が引き起こすもっとも共通した 問題は、spawn がプロシジャ内で実行された時である。プロシジャの外では、 spawn_id はスコープのため、もはや存在しないので spawn されたプロセスは単純には アクセス不能となる。そのようなプロセスには、"global spawn_id"を 付け加えねばならない。 multi-spawn 機能が使えない(つまり、あなたのシステムが select (BSD *.*), poll (SVR>2),または、それと等価なもの のいずれも サポートしていない)場合、 Expect は、同時に 1 プロセスしか制御できない。 この場合、 spawn_id を無理に設定したり、spawn されたプロセスが走っている間に exec を使って プロセスを実行したりしてはならない。さらに、複数のプロセス(片方が ユーザーでも)から同時に expect することもできない。

端末制御パラメタは、スクリプトに大きな影響を与える。例えば、 スクリプトがエコーを探すように書かれていれば、エコーをオフにすると 動作がおかしくなる。この理由で、Expect はデフォルトで 正気の 端末パラメタを設定する。不幸なことに、この設定が他のプログラムではまずい 場合がある。例えば、emacs シェルは"通常の"マッピングを変更しようとする。 : newlinesは、carriage-return newlines に変換されず newlines にマップされる。 そして、エコーは行なわれない。こうマップされることで、emacs は入力行を 編集できる。残念ながら、Expect はこのマッピングを検出できない。

Expect が端末パラメタのデフォルト設定を上書きしないように指定することが できるが、そういった環境で動かすスクリプトを書くときは細心の注意が 必要である。emacs の場合、エコーや改行コードのマッピングを回避しなければ ならない。

( expect とその変種、および、 interact といった)1 つのリストにブレースされた引数を受けとるコマンドは、 リストが引数をどれだけ持っているのかを判断するのに、発見的手法を用いる。 その発見的手法はが失敗する唯一の場合は、引数の一つに複数の\nが埋め込まれ、 その間にホワイトスペースがない場合である。これは十分検出不能な状態だが、 引数"-nobrace" で、強制的に一つの引数として扱うことができる。 自動的に生成された Expect コード中で使われるかもしれない。 同様に、-brace は複数のパターン/アクションをひとつの引数として扱うことを 強制する。

バグ
プログラムに "sex" ("Smart EXec" か "Send-EXpect" の略) という名前を つけるのは実に魅力的だったのだが、センスの良い方(あるいは、 単にピューリタニズム)が優先された。

シェルが spawn されるとttyにアクセスできないと文句をいって、しかし、動作はする というシステムがある。これは、このシステムがtty制御を得るための機構を 持っているが Expect はそれを知らないという意味である。どういう仕組みか調べて、その情報を私に 知らせてほしい。

Ultrix 4.1 (少なくとも最新バージョンのあたり) では、 1000000 を超えるタイムアウトを 0 とみなしてしまう。

Digital UNIX 4.0A (おそらく他のバージョンも)は SIGCHLD ハンドラを 定義すると、pty の割り付けを拒否する。詳細は grantpt ページを参照のこと。

IRIX 6.0 は、pty へのアクセス制御を正確に扱えない。それで、 Expect は、pty がアロケートできない場合は、他の人が前に使った pty の アロケートを試みる。 IRIX 6.1 にアップグレードすること。

telnet (SunOS 4.1.2 でのみ確認)は、TERM が設定されてないと ハングする。この問題は cron や at や CGI スクリプトで使う時に問題だ (設定しないので)。それで、 明示的に指定しなくてはならない - 本当のタイプは通常関係ない。 何かに設定してないと駄目なのだ! 以下の記述はおそらくほとんどの場合を 満足させるだろう。

set env(TERM) vt100

tipt (BSDI BSD/OS 3.1 i386 でのみ確認)は、SHELL と HOME が設定されてないと ハングする。この問題は cron や at や CGI スクリプトで使う時に問題だ (設定しないので)。それで、 明示的に指定しなくてはならない - 本当のタイプは通常関係ない。 何かに設定してないと駄目なのだ! 以下の記述はおそらくほとんどの場合を 満足させるだろう。

set env(SHELL) /bin/sh
set env(HOME) /usr/local/bin

pty のインプリメントの中には、プロセスがファイル記述子をクローズした後、 読んでない出力を 10 から 15 秒後(この値はインプリメントに依存)に投げてくる ものがある。それゆえ、

spawn date
sleep 20
expect

のような Expect プログラムは失敗する。失敗しないように非対話的なプログラムでは spawn せずに exec すること。こういう状況は考えられるが、実際には私はまだその状態に 陥ったことがない。つまり、この原因で対話プログラムの最後の出力を 取りこぼすという状態になったことがない。

一方、Cray UNICOS の pty は読み込んでいない出力をファイルディスクリプタを プロセスが閉じるとすぐに投げてくる。私は Cray にこの動きについて報告し、 回避するための修正を行なった。

プロンプトと応答の間にディレイが必要な場合がある。tty インターフェースが UART の設定を変えたり、スタート/ストップビットを探してボーレートを合わせて いる時などである。通常、ここで必要とされているものは 1 秒か 2 秒の待ち合わせである。 もっとしっかりしたやり方はハードウェアが入力を受ける準備ができるまで繰り返す ことである。以下の例は、両方の戦略を採用している。:

send "speed 9600\r";
sleep 1
expect {
timeout {send "\r"; exp_continue}
$prompt
}

-code をトラップするのは Tcl のイベントループに依存しているコマンド (sleep など)では動かない。 問題は、イベントループの中では Tcl は非同期イベントハンドラからの 返り値を捨てているからである。 回避方法としては、トラップコードでフラグをセットし、 コマンド(sleep など)の直後でフラグをチェックすることである。

EXPECT ヒント
Expect について、直観的でない点が少しある。 このセクションではそういったことの指摘とそれに対する示唆を試みる。

共通の expect の問題は、シェルプロンプトを認識する方法である。 その設定も、それを扱う人も、使うシェルもまちまちなので、実際に出てくる プロンプトを知らずに、汎用的に rlogin を自動化することは困難である。 妥当な線は、ユーザーにプロンプトにマッチする正規表現(特にプロンプトの 終りの部分)を環境変数 EXPECT_PROMPT に保存させることである。 以下のようなコードでできる。 EXPECT_PROMPT がなくても、コードは正しく動く可能性がある。

set prompt "(%|#|\\$) $" ;# default prompt
catch {set prompt $env(EXPECT_PROMPT)}

expect -re $prompt

私としては、見えると思っているものの終りの部分を含んだ expect パターンを書くように勧める。そうすれば、全体を見る前に応答を返してしまう ことを避けることができる。さらに、全体が見える前に答えることもできるが その文字は質問に混ざって echo される。言い替えれば、会話は正常だが見た目は 混ざって見える。

ほとんどのプロンプトの終りの文字はスペースである。例えば、 ftpからのプロンプトは、'f', 't', 'p', '>' そして である。 このプロンプトにマッチさせるには、この文字の一つ一つにマッチしなければ ならない。blank を含めないのは、よくある誤りである。明示的に blank を 入れるように。

X* の形のパターンを使うのであれば、* はXから最後に受けとる何かまでの 全てにマッチする。これは一見直観的だが、"最後に受けとる何か"が コンピュータの速度とカーネルとデバイスドライバによるI/O処理によって 変わってしまうので混乱するだろう。

特に、人間はプログラムの出力が巨大なひとまとまりとしてやってくると思いがち だが、実際には、ほとんどのプログラムは一行を一度に送る。 こう仮定すると、直前の段落のパターンにあった * は、行の終りにしか マッチしないかも知れない。たとえ、もっと入力があると思われる場合でも 出力を全て受けとった時点でしかマッチを行なわないのである。

expect は、指定したパターンが教えてくれない限り、出力がさらにやってくるのか どうかわからない。

行指向のバッファリングを行なっている場合ですら、賢いやり方とはいえない。 プログラムはバッファリングのタイプをめったに保証しないだけでなく、その際に 消化不良を起こして出力行を中断し、行末をバッファ中のランダムな位置に 置いてしまう。 それで、パターンを書く時には、プロンプトの最後の何文字かを入れておいた方が 賢いやり方といえるのである。

プログラムの最後の出力にあるパターンを待ち、実際には何がしか他のものが 発行されている場合には timeout キーワードで判定することができない。理由は、 expect が、タイムアウトしない - そのかわりに eof を見つけられる - からである。 代わりになるものを使うこと。もっと良いのは、両方使うことだろう。 行が回り込んだ場合でも、行そのものを編集するべきではない。

tty ドライバによって出力される時に newline は、普通 carriage return, linefeed の組に変換される。 それで、2 ラインにマッチするには、例えば、printf("foo\nbar") に マッチさせるには、"foo\r\nbar" というパターンを使うことになる。

似たような変換は、ユーザーから expect_user を通して入力を読み込む時にも起こる。この場合、ユーザーがリターンを 押すと、それは newline に変換される。その後、 Expect が端末モードを raw モード(telnet のような)を設定すると、問題が発生する 可能性がある。プログラムが本当のリターンを待ってしまうからである。(プログラムの 中には、newline をリターンに変えても大丈夫なものもあるが、ほとんどはだめである。) 残念ながら、プログラムが端末を raw モードにすることを検出する方法がない。

手で newline をリターンに変えるのではなく、"stty raw"を使うのが解決策である。 stty raw は、変換を停止する。しかし、こうすると cooked モードの行編集機能が 使えなくなるということに注意すること。

interact は、端末を raw モードに設定するので、この問題は発生しない。

Expect スクリプトの中でパスワード(や他の機密情報)を保存すると便利なことは よくある。だれかのアクセスを受けるとその影響を受けてしまうコンピュータで そういうことをするのは勧められない。それで、パスワードのプロンプトを スクリプトから出すのが、文字通りパスワードを埋め込むよりは、良い考えと いえる。とはいうものの、そういった埋め込みをするしかない場合もある。

不幸なことに、UNIX のファイルシステムは「実行可能で読めない」スクリプトを 作る直接の方法がない。setgid シェルスクリプトをサポートしたシステムでは、 次のようにすることで間接的にシミュレートできる。

, Expect スクリプト(機密情報の入った)を普通に作る。 そのパーミッションを 750 (-rwxr-x---) に設定し、trusted group つまり、読んでも良いグループ の所有とする。必要なら、この目的のための 新しいグループをつくること。次に、/bin/sh スクリプトを パーミッション
2751 (-rwxr-s--x) で、同じグループの所有で作成する。

こうすると、シェルスクリプトはだれからも実行でき(かつ、読め)る。 実行すると、それは Expect スクリプトを実行する。

関連項目

Tcl(3), libexpect(3)
"Exploring Expect: A Tcl-Based Toolkit for Automating Interactive Programs" by Don Libes, pp. 602, ISBN 1-56592-090-2, O'Reilly and Associates, 1995.
"expect: Curing Those Uncontrollable Fits of Interactivity" by Don Libes, Proceedings of the Summer 1990 USENIX Conference, Anaheim, California, June 11-15, 1990.
"Using expect to Automate System Administration Tasks" by Don Libes, Proceedings of the 1990 USENIX Large Installation Systems Administration Conference, Colorado Springs, Colorado, October 17-19, 1990.
"Tcl: An Embeddable Command Language" by John Ousterhout, Proceedings of the Winter 1990 USENIX Conference, Washington, D.C., January 22-26, 1990.
"expect: Scripts for Controlling Interactive Programs" by Don Libes, Computing Systems, Vol. 4, No. 2, University of California Press Journals, November 1991.
"Regression Testing and Conformance Testing Interactive Programs", by Don Libes, Proceedings of the Summer 1992 USENIX Conference, pp. 135-144, San Antonio, TX, June 12-15, 1992.
"Kibitz - Connecting Multiple Interactive Programs Together", by Don Libes, Software - Practice & Experience, John Wiley & Sons, West Sussex, England, Vol. 23, No. 5, May, 1993.
"A Debugger for Tcl Applications", by Don Libes, Proceedings of the 1993 Tcl/Tk Workshop, Berkeley, CA, June 10-11, 1993.

著者
Don Libes, National Institute of Standards and Technology

謝辞
Tclを生み出した John Ousterhout と、インスピレーションを与えてくれた Scott Paisley に感謝する。 Expect のオートコンフィギュレーションコードについて、 Rob Savoye に感謝する。

HISTORY ファイルに expect の進化の大部分が記述されている。このファイルは面白く読めて、かつ、 あなたのこのソフトウェアへの洞察をより深くするだろう。このファイルに 書かれている、私にバグフィックスを送ってくれた人たちや、他の援助を してくれた人たちに感謝する。

Expect の設計と実装は、部分的にアメリカ政府からその対価をもらっているので、 パブリックドメインである。しかし、このプログラムとドキュメントあるいは その一部が使われたなら、著者と NIST への謝辞を述べてもらいたい。

参考URL 感謝です。

シェルスクリプトでユーザー作成
Expectの書き方
ExpectをつかってRsyncの起動

WordPress 投稿一覧で表示する記事の文字数を制御する

読了までの目安時間:約 1分

WordPress の投稿一覧で more タグを挿入すると、区切りのいいところまで表示して ’続きを観る’と表示してくれます。

いちいち、moreタグなんか入れたくない場合は テンプレートファイルのthe_content()関数やthe_excerpt()関数のところを変更します。

上記さんぷるのページです。

WordPress Codex日本語版にthe_excerpt() と the_content() についてに書かれています。「続きを読む」のカスタマイズにも大切な情報が書かれています。

WP Multibyte Patch

WP Multibyte Patch という素晴らしいWordPress のプラグインがあります。

Linux のユーザー一括削除をスクリプトで

読了までの目安時間:約 3分

入社、退社が激しい会社や学校のサーバのメンテナンスをしていると、ユーザーの一括登録や一括削除をしたい時があります。

userdel コマンド manより

名前
userdel - ユーザのアカウントと関連ファイルを削除する

書式
userdel [-r] login

説明
userdel コマンドは、システムアカウントファイルを修正し、ユーザ login に対応するすべてのエントリを削除する。削除されるユーザは存在していなければならない。 userdel コマンドに適用できるオプションは以下の通り。

-r ユーザのホームディレクトリ中のファイルを削除する。ホームディレクトリ自体とユーザのメールスプールも消去する。ファイルシステム中のほかの場所にあるそのユーザのファイルは、手作業で探し出して削除しなければならない。

ファイル
/etc/passwd - ユーザアカウント情報
/etc/shadow - 安全なユーザアカウント情報
/etc/group - グループ情報

警告
userdel は、削除されるユーザが現在ログインしている場合は、そのアカウントの削除を許可しない。削除しようとしているアカウントに属する実行中のプロセスは、すべて kill しなければならない。 NIS のクライアントからは、NIS の属性値は削除できない。削除は NIS のサーバで行わなければならない。

関連項目
chfn(1), chsh(1), passwd(1), groupadd(8), groupdel(8), groupmod(8),
useradd(8), usermod(8)

著者
Julianne Frances Haugh (jockgrrl@ix.netcom.com)

一括削除スクリプト

#!/bin/sh
LIST=./user.txt

while read USER
do
/usr/sbin/userdel -r {USER}
don < ${LIST}

userdel の -r オプションで、アカウントの削除と同時にホームディレクトリ中のファイルも削除しています。

vpopmailを使っている方は userdel 部分を変更すれば一括削除ができますね。

メールサーバ qmail or postfix & dovecot

読了までの目安時間:約 3分

postfix & dovecot をインストールする前に google で検索です。

qmail + vpopmail という構成ででメールサーバを構築していましたが、さすがに qmail をインストールするのも大変になってきたので、メールサーバの構築をどのようにするか検討中です。

vpopmail の利点のひとつに Linux のアカウントによらないドメイン&ユーザーの管理があります。
新規のインストールではなく、旧環境(ユーザー&パスワード)を移行しようと思うと大変な作業になる可能性があるので、良い方法がないか google で検索してみました。

ワリと古いqmail+vpopmail環境をPostfix+Dovecotに移行したいよ話。

CentOS に postfix & dovecot を新規インストール&設定する場合は下記URLがわかりやすかったです。

http://www.server-world.info/query?os=CentOS_6&p=mail

という構成で説明されています。

今後の予定

パソコンが一台あまっているので、新たに Linux をインストールし、以前の環境も移行しようと思っています。ただ、メールサーバなど新しいものに移行する時期にきているので、テストしながら移行する予定です。

参考URL

CentOSで自宅サーバ構築

WordPress やっぱり便利です

読了までの目安時間:約 3分

WordPress (ワードプレス) は、オープンソースのブログ/CMS プラットフォームです。セマンティック Web、コードやデザインの美しさ、Web 標準、ユーザビリティなどを意識して開発されており、無料でダウンロードして使うことができます。

プロフェッショナルな方々の圧倒的な支持を得ています WordPress


2012年4月のデータです。
情報元 http://royal.pingdom.com/2012/04/11/wordpress-completely-dominates-top-100-blogs/

ライセンスおよび動作環境

WordPress は GPL に基づいて使用できます。GPL ライセンスについてGPLやMITやCCなど主要ライセンスの内容と意味のまとめにまとめられています。

GPL(GNU General Public License) は上記GPLライセンスの制約を若干緩めたもので、主にライブラリやモジュールみたいなものに使用されているライセンスです。

GPLライセンスとの違いは、「動的リンクとして使用した場合は、そこ以外の部分にはLGPLライセンスを適応させなくていいよ」というところ。

動的リンクするプログラムというと、windowsでいえば「.dll」という拡張子のファイルとかですね。実行ファイルである「.exe」とかと一緒によく入ってるヤツです。

つまり、あなたが制作した「B」というソフトウェア(実行ファイル「abc.exe」内部も完全自作)で「C」というLGPLライセンスのものを使用したい場合、その「C」を、外部ファイルとして「xyz.dll」みたく使用するなら、そこ以外の部分はLGPLは関与しないよ、という事。

しかし、本体である「abc.exe」の中にLGPLライセンスのものを直接使用した場合は、これまた全てLGPLライセンスにしなければいけません。

詳細については GNU General Public License ウィキペディアをご覧ください。
WordPress の動作環境は プラットフォーム:PHP Ver.4.3 以上 + MySQL ver.4.0 以上とされています。

WordPress Lesson

このサイトは、WordPress のカスタマイズ方法や便利なプラグイン、綺麗なテンプレートの紹介などをしていきます。公開まであと少し!!
お楽しみに。

参考URL

WordPress Codex日本語版
WordPress の機能
WordPressでブログじゃないWebサイトを作るときのいろいろ(サンプル付き)

複数ファイル内文字列を一括置換する

読了までの目安時間:約 4分

スクレイピング

Webページから欲しい情報だけを取ってきて、スクリプトやプログラムで集計したりグラフ化する事がよくあります。Webページの中から情報を削り取ることから、Webページから欲しい情報だけを取ってくる事をスクレイピングといいます。

複数ファイル内文字列を一括置換する

取得したテキストベースの情報の文字列を一括で置換したい時がよくあります。

#!/bin/sh
for f in *.txt
do
perl -pi -e 's|hogeorg|hogenew|g' $f
done

複数あるファイルの拡張子を、一度に変更したい時は次のようにしています。 (例:ファイルの拡張子 htm を html に変更)

for f in *.htm
do
mv $f `basename $f .htm`.html
done

basename コマンド man より

名前
basename - ファイル名からディレクトリと拡張子を取り去る
書式
basename name [suffix]
basename [--help] [--version]
説明
basename は name から、前の方にあるディレクトリの部分をすべて取り去る。

suffix が指定され、それが name の末尾と一致すると、その部分も name から同時に除去される。 basename は結果の名前を標準出力に表示する。
オプション
--help 標準出力に使用方法のメッセージを出力して正常終了する。
--version
標準出力にバージョン情報を出力して正常終了する。
注意
プ ログラムのバグについては bug-sh-utils@gnu.org に報告してください。ページの更新は Ragnar Hojland Espinosa が行っています。

* シェルスクリプト内で、「basename $0」と記述すると、シェル自身のファイル名のみを調べることができます。

PHPやC 言語に慣れているとシェルスクリプトでの変数の扱いにとまどうかもしれません。シェルスクリプトで変数を定義する場合は、前もって変数を宣言する必要はなく'='の両側にスペースをあけてはいけません。変数の先頭に'$'をつけて格納された値を参照します。
演算子と数字の間はかならずスペースをあけなくてはいけないなどの決まりがあります。

シェルの変数については第5回 シェルの変数に慣れるなどを参考にされるとよいでしょう。

参考URL

スクレイピングとは
phpによるスクレイピング処理入門
bashで始めるシェルスクリプト基礎の基礎

Gmail の Google API を使ってみました

読了までの目安時間:約 3分

Gmail の APIを使って何か面白い事が出来ないかなぁと思いついたけど、まず Google API についてほとんどわかっていなかったので google で一生懸命検索しました。
What is the service name in ClientLogin for each Data API?で、ザクッとどのくらいサービスがあるかを確認するところから始まりました。

cURLとは?

 cURL (Client URL Library) は、プログラムやコマンドラインからアクセスできる Webブラウザのようなものです。cURL を使うと FTP や HTTP などのプロトコルを通じて外部サーバーとアクセスし、ファイルのダウンロードやアップロードなどを行うことができます。 cURL は Cookie やプロキシ、SSL、各種の認証機構などもサポートしています。

cURL をコマンドラインで使う

$ curl http://hoge.com

gmail.com から Authを取得

curl -s https://www.google.com/accounts/ClientLogin \
-d Email=hoge@hoge.com \
-d Passwd=hogepasswd \
-d accountType=GOOGLE \
-d source=mail \
-d service=mail | grep ^Auth= | sed 's/^Auth=//'


DQAAAOkAAACXdPYOAHDyn5AUX0hQhzIbrVZrd6cvWa-OwS-K07Ux628w_giNu05nd3EEPrw7VVnn8nD2q277VLg1a1IsD8-otxIOeSygP-WqEHlnNKLF-DERURMv2jvsqJwSLc0tcYWozUzdxSjyc0KDHNsr8mt3755Vv1vxtf3ATBUq3tnvRJl-1P9pUNsbKmDi0_HRr_BQ9sgSlh21FxApFLWpQOi9bB5MESqQxnKC4hA6Sk6EyKNQrpC9IZkbCTiTNl2tPb4bj8QLQvYwWjoHiGHMRjxZBOn0UpPGjAdBBG50pXuPrZtpmE6-9Gw0s-vmhRm0Ip0

curl -u hoge@hoge.com:hogepass --silent "https://mail.google.com/mail/feed/atom" | tr -d '\n' | awk -F '' '{for (i=2; i<=NF; i++) {print $i}}' | sed -n "s/\(.*\)<\/title.*name>\(.*\)<\/name>.*/\2 - \1/p"</pre>
<h3>Gmail の Google APIs </h3>
<p><b>Gmail ATOM Feeds</b><br />
 Gmail の受信トレイや特定のラベルの内容を取得する Atom フィード。<br />
<b>Gmail Greasemonkey API</b><br />
 Firefox の Greasemonkey を使って Gmail を拡張できる。<br />
<b>Google Contacts Data API</b><br />
 Gmail のコンタクト情報(住所録)の取得や更新などが行える。グループの管理も可能。最近では他のサービスでもこのコンタクト情報が利用されている。</p>
<h3>cURL を使って gmail から読み出す</h3>
<table cellpading="3">
<tr>
<td>
curl -u hoge@hoge.com:hogepasswd --silent "https://mail.google.com/mail/feed/atom"
</td>
</tr>
</table>
<pre lang="xml">
<?xml version="1.0" encoding="UTF-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#">
<title>Gmail - Inbox for hoge@hoge.com
New messages in your Gmail Inbox
43

2012-06-02T10:52:28Z

【Smart-C通信】新着案件情報や停止案件情報など
Smart-C通信(2011/07/04号 ...

2011-07-04T11:50:25Z
2011-07-04T11:50:25Z
tag:gmail.google.com,2004:9993404110060528187

Smart-C事業部
media_info@smart-c.jp


【Smart-C通信】新着案件情報や停止案件情報など
Smart-C通信(2011/06/08号 ...

2011-06-08T09:37:06Z
2011-06-08T09:37:06Z
tag:gmail.google.com,2004:9991040200740104742

Smart-C事業部
media_info@smart-c.jp


参考URL 感謝です。

PHP で Google Apps の OAuth 認証を使う
gmail-greasemonkey
Gmailフィードのまとめ
curlを使ってコマンドラインからGDataにログインし、picasaに画像をアップロードする
curlやwgetでGoogle Data Serviceの認証を受ける
Gmailを拡張する「Gmail Contextual Gadget」の作り方
Check your unread Gmail from the command line
Using cURL to interact with Google Data services
What is the service name in ClientLogin for each Data API?

無料メルマガ登録
最近の投稿