ファイルテスト演算子

ファイルがあるかないか,読めるか,書けるか,空か,など 指定したファイルの状態を調べるための組み込み関数 test がある。

testの用法

test は,

test(cmd, file1 [, file2])

の書式で用い,指定したファイル file1cmd の要件を満たすかどうかを返す。2つのファイルの 関係を調べるための cmd には第3引数 file2 を与える。

cmd働き
?r現在の実行uidで読めるか
?w現在の実行uidで書き込めるか
?x現在の実行uidで実行できるか
?o現在の実行uidが所有するファイルか
?G現在の実行gidと同じグループ所有か
?R実 uid で読めるか
?W実 uid で書き込めるか
?X実 uid で実行できるか
?O実 uid が所有するファイルか
?e存在するか
?s0バイトでないか(サイズが返る)
?f普通のファイルか
?dディレクトリか
?lシンボリックリンクか
?p名前付きパイプ(FIFO)か
?bブロックデバイスファイルか
?cキャラクタデバイスファイルか
?usetuidビットがセットされているか
?gsetgidビットがセットされているか
?kstickyビットがセットされているか
?M最終更新時刻を返す
?A最終アクセス時刻を返す
?Cinode時刻を返す
以下は第2,第3引数間の比較
?-両ファイルが同一か
?=両ファイルの最終更新時刻が等しいか
?>file1の 最終更新時刻がfile2より大きい(新しい)
?<file1の 最終更新時刻がfile2より小さい(古い)

testの利用例

実行結果を決まった名前のファイルに保存するようなコマンドを考える。 たとえば,おみくじの結果をカレントディレクトリの fortune.txt に保存するプログラムがあったとする。

ft0.rb

#!/usr/bin/env ruby
# coding: euc-jp
#Foretune teller - version 0
ftune	= %w,大吉 吉 中吉 小吉 半吉 末吉 小凶 凶,
outfile	= "fortune.txt"
srand
result = ftune[rand(ftune.length)]
open(outfile, "w") do |f|
  f.printf("今日の運勢は %s\n", result)
end
STDERR.puts "#{outfile}を見よ。"

このプログラムを最初に起動するときは問題がない。しかし, 実行すると結果ファイルを上書きするので,以下のような問題がある。

改良してみる。

上記2点の改良を施してみよ。

すべてのファイルに対しての処理

あるディレクトリ以下にあるすべてのファイルに対して特定の処理を 行なうことはしばしば必要となる。そのための手順の流れは 以下のようになる。

  1. あるディレクトリを開きすべてのファイルについて以下を繰り返す
  2. それがファイルなら特定の処理を行なう
  3. それがディレクトリならそのディレクトリに対してこの処理全体を行なう

特定の処理をメソッド化し,処理対象がディレクトリなら再帰処理を 行なう。以下のプログラムは,指定したディレクトリ (省略時はカレントディレクトリ)以下すべてのファイルに対して, それが通常ファイルならバックアップファイルを作成する。。

mkbak-r.rb

#!/usr/bin/env ruby
# coding: euc-jp
dir = ARGV.shift || "."

def cp(from, to, bufsize=8192)
  open(from, "r") do |src|
    open(to, "w") do |dest|
      while s = src.read(bufsize)
        dest.write s
      end
    end
  end
end

def bakdir(dir)
  ext = ".bak"
  Dir.foreach(dir) do |f|
    file = File.expand_path(f, dir)
    case f
    when ".", ".."              # カレントディレクトリと親ディレクトリ
      next                      # は飛ばす
    when %r,#{ext}$,		# それが既にバックアップファイルなら
      next  			# やはり飛ばす
    else
      if test(?d, file)         # ディレクトリなら
        bakdir(file)		# 再帰的に自分を呼ぶ
      elsif test(?f, file)      # 通常ファイルなら
        # バックアップファイル作成
        bak = File.expand_path(f+".bak", dir)
        File.unlink(bak) if test(?e, bak)
        cp(file, bak)
      end
    end
  end  
end

bakdir(dir)

本日の目次

yuuji@e.koeki-u.ac.jp