ruby [-l] [-s] script_file [file...]
Ruby はテキストフィルタとしての利用だけでなく、汎用なシステム操作記述言語としての利用に十分な組み込み関数や拡張モジュールが充実しており、シェル環境で足りない機能を外部コマンドとして拡充するだけの能力が備わっている。
Ruby スクリプトを外部コマンドとして利用する為には、Unix 環境では以下のような行頭から始めればよい。
#!/usr/bin/ruby :
また、コマンドラインオプションを指定するには、以下のように ruby -s
のように起動すれば、そのコマンドに指定したオプションが変数として定義されるようになる。
#!/usr/bin/ruby -s :
Ruby には多様な拡張ライブラリが備わり、その上、RubyGems.org では数多のサードパーティ製拡張ライブラリが用意されている。インストール済みの拡張ライブラリを利用するには、以下のようにする。
#!/usr/bin/ruby
require 'etc'
:
代表的な Unix コマンドに相当する Ruby スクリプトを以下にあげる。
Ruby では '-l'
オプションで print メソッドで自動的に改行がなされ、$, =
で配列やリストのフィールドセパレータがスペースになる。
' '
#!/usr/bin/ruby -l
$, = ' '
print ARGV
このように、echo と同じ ruby
スクリプトファイルは以上のようになる。
Ruby における終了コードは特に明示しない限り、正常終了である。
#!/usr/bin/ruby
このように、true と同じ ruby
スクリプトファイルは以上のようになる。
Ruby における終了コードは 'exit'
カーネルモジュール関数で指定できる。ちなみに、GNU Awk では可能だが、Awk では終了コードを制御できない。
#!/usr/bin/ruby exit 1
このように、false と同じ ruby
スクリプトファイルは以上のようになる。
#!/usr/bin/ruby -l -s print $u ? Time.now.gmtime.strftime("%c") : Time.now.localtime.strftime("%c")
このように、date と同じ ruby
スクリプトファイルは以上のようになる。
#!/usr/bin/ruby -l ARGV[0] or abort "usage: dirname path" print File.dirname(ARGV[0])
このように、dirname と同じ ruby
スクリプトファイルは以上のようになる。
#!/usr/bin/ruby -l ARGV[0] or abort "usage: basename string [suffix]\n basename [-a] [-s suffix] string [...]" if (ARGV[1]) print File.basename(ARGV[0], ARGV[1]) else print File.basename(ARGV[0]) end
このように、basename と同じ ruby
スクリプトファイルは以上のようになる。
#!/usr/bin/ruby -l
require 'etc'
name = Etc::getpwuid(Process::UID.rid).name || Etc.getlogin || Etc.getpwuid().name
print name
このように、logname と同じ ruby
スクリプトファイルは以上のようになる。
#!/usr/bin/ruby -s require'etc'
gids, gnames = [], {} if (!ARGV[0]) $id = Process::UID.eid gids.push(Process::GID.eid) Process.groups.each {|group| gids.push(group) } gids.shift if ($G) else if (ARGV[0] !~ /^\d+$/) $name, $id = Etc::getpwnam(ARGV[0]).values_at(0, 2) exit 1 if (!$name) else $id = ARGV[0].to_i end $name, $gid = Etc::getpwuid($id).values_at(0, 3) exit 1 if (!$name) gids.push($gid) while (grent = Etc::getgrent) gname, gid, members = grent.values_at(0, 2, 3) members = (members.map {|member| Etc::getpwnam(member)[2] }).find_all {|id| id == $id } gids.push(gid) if (members.length > 0) end end if ($G) $, =' '
if (!$n) print gids if (gids.length > 0) else print gids.map {|gid| Etc::getgrgid(gid)[0] } if (gids.length > 0) end elsif ($g) if (!$n) print gids[0] else $gname = Etc::getgrgid(gids[0])[0] exit 1 if (!$gname) print $gname end elsif ($u) if (!$n) print $id else $name = Etc::getpwuid($id)[0] exit 1 if (!$name) print $name end else $name, $gid = Etc::getpwuid($id).values_at(0, 3) exit 1 if (!$name) $gname = Etc::getgrgid($gid)[0] exit 1 if (!$gname) printf "uid=%u(%s) gid=%u(%s) ", $id, $name, $gid, $gname print "groups=" gids.length.times do |i| if (!gnames[gids[i]]) gname = Etc::getgrgid(gids[i])[0] print "," if (i != 0) printf "%u(%s)", gids[i], gname gnames[gids[i]] = gname end end end print "\n"
このように、id と同じ ruby
スクリプトファイルは以上のようになる。
#!/usr/bin/ruby -s
time = Time.now;
if ($r)
stat = File::Stat.new($r);
else
if ($t)
if ($t =~ /(?:((?:\d{2})?\d{2}))?(\d{2})(\d{2})(\d{2})(\d{2})(?:\.(\d{2}))?$/)
_CCYY, _MM, _DD, hh, mm, _SS = $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i;
if (_CCYY)
if (_CCYY <= 99)
_CCYY += (69 <= _CCYY) ? 1900 : 2000
end
else
_CCYY = (Time.localtime(time))[5] + 1900
end
_SS = 0 if (!_SS);
time = Time.local(_CCYY, _MM, _DD, hh, mm, _SS);
end
end
end
if ($a && $m || !$a && !$m)
atime = $r ? stat.atime : time;
mtime = $r ? stat.mtime : time;
elsif ($a)
atime = $r ? stat.atime : time;
elsif ($m)
mtime = $r ? stat.mtime : time;
end
ARGV.each do |$_|
if (!$c && !File::exists?($_))
f = open($_, 'w'
) rescue abort("create failure for #{$_}: #{$!}")
f.close
atime ||= mtime
mtime ||= atime
end
atime ||= time
mtime ||= time
File::utime(atime, mtime, $_) rescue abort("touch failure for #{$_}: #{$!}")
end
このように、touch と同じ ruby
スクリプトファイルは以上のようになる。
`du` コマンドを実現するには 'opendir'
, 'readdir'
, 'closedir'
及び 'stat'
, 'lstat'
を使えれば十分だ。Ruby にはそれに対応する 'Dir::entries'
, 'File::stat'
, 'File::lstat'
がある。
#!/usr/bin/ruby $units = {'K'
=> 1024, # KibiBytes'M'
=> 1024*1024, # MebiBytes'G'
=> 1024*1024*1024, # GibiBytes } $S = 1 while (ARGV.length > 0) if (ARGV[0] =='--'
) then ARGV.shift; break elsif (ARGV[0] =='-H'
) then $H = true elsif (ARGV[0] =='-L'
) then $L = true elsif (ARGV[0] =='-a'
) then $a = true elsif (ARGV[0] =='-s'
) then $s = true elsif (ARGV[0] =='-d'
&& 1 < ARGV.length) then ARGV.shift; $d = ARGV[0].to_i elsif (ARGV[0] =='-k'
) then $S = 2 elsif (ARGV[0] =='-m'
) then $S = 2*1024 elsif (ARGV[0] =='-g'
) then $S = 2*1024*1024 elsif (ARGV[0] =='-h'
) then $h = true else break end ARGV.shift end def resize(size) if (!$h) (size/$S).ceil else if (!(size < $units['G'
]/512)) p ='G'
elsif (!(size < $units['M'
]/512)) p ='M'
else p ='K'
end s = size/($units[p]/512) p ='B'
if (s < 1) f = "%3.0f" f = "%3.1f" if (!(s < 1) && s < 10) sprintf(f, s) + p end end @total_sizes = [ 0.0 ] def do_one(one) size = 0 if (File::directory?(one) && ($L || (!$L && !File::symlink?(one)))) return if (!(File::readable?(one) && File::executable?(one))) @total_sizes.push(0.0) Dir::entries(one).each do |entry| next if (entry =='..'
) next if (entry =='.'
) do_one("#{one}/#{entry}") end rescue warn("cannot opendir #{one}: #{$!}") size = @total_sizes.pop print resize(size), "\t", one, "\n" if ((!$s || ($s && @total_sizes.length-1 == 0)) && (!$d || !($d < @total_sizes.length-1))) else return if (!(stat=($L && File::exists?(one) ? File::stat(one) : File::lstat(one)))) size = stat.blocks print resize(size), "\t", one, "\n" if ($a) end @total_sizes[@total_sizes.length-1] += size end unless (ARGV.length > 0) do_one('.'
) exit 0 end while (ARGV.length > 0) do_one(ARGV[0]) ARGV.shift end
このように、du と同じ ruby
スクリプトファイルは以上のようになる。