Ruby で which 書いてみた

which[q-e-d.net] ってのは、コマンドのパスを調べるコマンドなんだって〜。
偶然、whichコマンドを作る[atmarkit.co.jp] なんてページを発見したので、
Ruby で書き直そうと思う。

bat バージョンがこちら:

@echo off
for %%I in (%1 %1.com %1.exe %1.bat %1.cmd %1.vbs %1.js %.wsf)
if exists %%~$path:I echo %%~$path:I

環境変数である PATH には、「パスを通」されてる絶対パスが `;' で区切られて入ってる。
だから、指定された実行可能な(プログラム|スクリプト)名を調べるには、そのパスを巡回していって、検索していけばいいわけだ。
ってのが解ったので Ruby で書いてみた:

# encoding: shift_jis

if ARGV.length > 0 then
  target_name = ARGV[0]

  paths       = ENV["PATH"].split( /;/ ).collect { |x| x.gsub( /\\/, "/" ) }
  pattern     = Regexp.compile( "^#{target_name}\.(com|exe|bat|cmd|vbs|js|wsf)?$" )

  paths.each do |path|
    Dir.foreach(path) do |file|
      unless (file =~ pattern).nil? then
        puts "/#{path.gsub(/\\/, '/')}/#{file}"
        exit  # -- (1)
      end
    end
  end
end

ちょっとだけ解決編

ENV は、環境変数をハッシュにしたものだよ。
paths のとこでは環境変数の中の PATH にあくせく*1して、それをセミコロン(;) で分割して paths に入れてるね。
ああ、 collect の部分は円マークをスラッシュに変換してるだけ。簡単でしょ?
# だって、円マークウザくね?

pattern は指定されたコマンド名に実行用の拡張子がついたりつかなかったりする文字列にマッチしそーな正規表現リテラル
paths をどんどん回して、そのディレクトリの中に pattern がマッチするのがあったら フルパスを表示して which 終了。

*1:アクセスのこと