やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

組込ライブラリ(Dir)

 ディレクトリ操作するクラス。

成果物

情報源

Dir

 ディレクトリ操作するクラス。Enumratableを継承している。

特異メソッド

[] chdir children chroot delete each_child empty? 
entries exist? exists? foreach getwd glob 
home mkdir new open pwd rmdir unlink

インスタンスメソッド

children close each each_child fileno 
inspect path pos pos= read rewind seek tell to_path

[], glob

 ワイルドカード展開する。パターンにマッチしたファイル名を配列で返す。ディレクトリ、ファイル、リンク等にヒットする。

Dir.glob("*")                      #=> ["bar", "foo"]
Dir.glob("*", File::FNM_DOTMATCH)  #=> [".", "..", "bar", "foo"]
Dir.glob('*') {|f| p f}

 APIは以下。

self[*pattern, base: nil, sort: true] -> [String][permalink][rdoc][edit]
glob(pattern, flags = 0, base: nil, sort: true) -> [String]
glob(pattern, flags = 0, base: nil, sort: true) {|file| ...} -> nil

 patternには以下のメタ文字が使える。

メタ文字 概要
* 空文字列を含む任意の文字列。
? 任意の一文字
[] 鈎括弧内のいずれかの文字。-で範囲[a-z]^!で否定[^abc]
{} 組合せ展開。a{1,2,3}=a1,a2,a3{}はネストできる。
**/ ディレクトリの再帰的マッチ。

 flagsにはFile::Constantsを指定する。

File::Constants 概要
FNM_CASEFOLD アルファベットの大小文字を区別しない
FNM_DOTMATCH ワイルドカード *, ?, [] が先頭の . にマッチするようになる
FNM_NOESCAPE エスケープ文字 `\' を普通の文字とみなす
FNM_PATHNAME ワイルドカード *, ?, []/ にマッチしなくなる。シェルと同等
FNM_SYSCASE case hold なファイルシステムの場合、FNM_CASEFOLD の値になり、そうでなければゼロ。

chdir

 カレントディレクトリを変更する。成功すると0を返す。

Dir.chdir('/tmp')
p Dir.pwd #=> /tmp

 ブロックがあるとカレントディレクトリの変更はブロック内のみとなる。

Dir.chdir('/tmp')
Dir.chdir('/tmp/work') {|path|
  p path #=> /tmp/work
  p Dir.pwd #=> /tmp/work
}
p Dir.pwd #=> /tmp

children, each_child, entries, foreach

 指定したパスがもつ子の名前一覧を配列で返す。.,..を除く。Encodingを指定しなければファイルシステムのそれになる。

Dir.children('/tmp/work')
Dir.children('/tmp/work', encoding:Encoding::UTF_8)

 インスタンスメソッド版もある。引数なし。

Dir.open('.'){|d|
  p d.children # => ["bar", "foo"]
}

 ループ版もある。同様にEncodingを指定できる。

Dir.each_child('.'){|f|
  p f
}
#=> "bar"
#   "foo"

 ...を含む版。同様にEncodingを指定できる。

Dir.entries('.') #=> [".", "..", "bar", "foo"]

 同上の別名版。配列でなくEnumratorを返す。

Dir.foreach('.').to_a
Dir.foreach('.') {|f| p f}

chroot

 ルートディレクトリを変更する。スーパーユーザだけが変更できる。

Dir.chroot("./")

 権限がないと以下のように怒られる。

Operation not permitted @ dir_s_chroot - ./ (Errno::EPERM)

 ディレクトリを削除する。ディレクトリは空でなければならない。成功すると0を返す。

Dir.mkdir '/tmp/work/test'
Dir.delete '/tmp/work/test'

Dir.mkdir '/tmp/work/test'
Dir.rmdir '/tmp/work/test'

Dir.mkdir '/tmp/work/test'
Dir.unlink '/tmp/work/test'

empty?

 ディレクトリが空のとき真を返す。

Dir.mkdir '/tmp/work/test'
Dir.rmdir if Dir.empty? '/tmp/work/test'

exist?

 ディレクトリが存在するなら真を返す。

d = '/tmp/work/test'
Dir.mkdir d unless Dir.exist? d

 なお、File.directory?も同様。

d = '/tmp/work/test'
Dir.mkdir d unless File.directory? d

getwd, pwd

 カレントディレクトリのフルパスを返す。

Dir.chdir("/tmp")   #=> 0
Dir.getwd           #=> "/tmp"
Dir.pwd             #=> "/tmp"

home

 現在のユーザまたは指定されたユーザのホームディレクトリを返す。

Dir.home
Dir.home('username')

Dir.home や Dir.home("root") は File.expand_path("~") や File.expand_path("~root") とほぼ同じです。

 File.expand_path絶対パスに展開した文字列を返す。

p Dir.getwd                      #=> "/home/matz/work/foo"
p ENV["HOME"]                    #=> "/home/matz"
p File.expand_path("..")         #=> "/home/matz/work"
p File.expand_path("..", "/tmp") #=> "/"
p File.expand_path("~")          #=> "/home/matz"
p File.expand_path("~foo")       #=> "/home/foo"

mkdir

 ディレクトリを作成する。

mkdir(path, mode = 0777) -> 0
p File.umask                                  #=> 2
Dir.mkdir('t', 0666)
p "%#o" % (07777 & File.stat('t').mode)  #=> "0664"
p File.umask                                  #=> 2
Dir.mkdir('t', 0666)
p "%#o" % (07777 & File.stat('t').mode)  #=> "0664"

new, open

 ディレクトリのストリームを開いて返す。

new(path) -> Dir
new(path, encoding: Encoding.find("filesystem")) -> Dir
open(path) -> Dir
open(path, encoding: Encoding.find("filesystem")) -> Dir
open(path) {|dir| ...} -> object
open(path, encoding: Encoding.find("filesystem")) {|dir| ...} -> object

ブロックを指定して呼び出した場合は、ディレクトリストリームを引数としてブロックを実行します。ブロックの実行が終了すると、ディレクトリは自動的にクローズされます。ブロックの実行結果を返します。

Dir.new('/tmp') {|dir| p dir}
Dir.open('/tmp') {|dir| p dir}

 ブロックがあれば自動的にcloseされるのが嬉しい。C#でいうusing(){}でありPythonでいうwith open() as f:

疑問

所感

 実際にコードを書くとなると色々疑問が出てきそう。そのときに都度調べよう。今はAPIをさらっと把握するだけに留める。

対象環境

$ uname -a
Linux raspberrypi 5.10.52-v7l+ #1441 SMP Tue Aug 3 18:11:56 BST 2021 armv7l GNU/Linux