私のスクリプトは外部プログラムとスクリプトに大きく依存しています。呼び出す必要があるプログラムが存在することを確認する必要があります。手動で、コマンドラインで「which」を使用してこれを確認します。
File.exists?
にあるものに$PATH
に相当するものはありますか?
(はい、私は%x[which scriptINeedToRun]
を解析できたと思いますが、それは非常にエレガントではありません。
ありがとう!ヤニック
更新:私が保持した解決策は次のとおりです。
def command?(command)
system("which #{ command} > /dev/null 2>&1")
end
真のクロスプラットフォームソリューションは、Windowsで適切に動作します。
# Cross-platform way of finding an executable in the $PATH.
#
# which('Ruby') #=> /usr/bin/Ruby
def which(cmd)
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
exts.each { |ext|
exe = File.join(path, "#{cmd}#{ext}")
return exe if File.executable?(exe) && !File.directory?(exe)
}
end
return nil
end
これはホストOSスニッフィングを使用せず、Windows上の実行可能ファイルの有効なファイル拡張子をリストする$ PATHEXTを尊重します。
which
へのシェルアウトは多くのシステムで機能しますが、すべてではありません。
使用する - find_executable
stdlibに含まれるmkmf
のメソッド。
require 'mkmf'
find_executable 'Ruby'
#=> "/Users/narkoz/.rvm/rubies/Ruby-2.0.0-p0/bin/Ruby"
find_executable 'which-Ruby'
#=> nil
def command?(name)
`which #{name}`
$?.success?
end
最初は hub から取得しましたが、which
の代わりにtype -t
を使用しました(zshとbashの両方で失敗しました)。
すでに多くの良い答えがありますが、私が使用するものは次のとおりです。
require 'mkmf'
def set_mkmf_log(logfile=File::NULL)
MakeMakefile::Logging.instance_variable_set(:@logfile, logfile)
end
# Return path to cmd as a String, or nil if not found.
def which(cmd)
old_mkmf_log = MakeMakefile::Logging.instance_variable_get(:@logfile)
set_mkmf_log(nil)
path_to_cmd = find_executable0(cmd)
set_mkmf_log(old_mkmf_log)
path_to_cmd
end
これは、ドキュメント化されていない#find_executable0メソッドを使用して MakeMakefile#find_executable によって呼び出され、標準出力を乱雑にすることなくパスを返します。 #whichメソッドは、一時的にmkmfログファイルを/ dev/nullにリダイレクトして、「mkmf.log」などで現在の作業ディレクトリが乱雑になるのを防ぎます。
ENVハッシュを使用してシステム環境変数にアクセスできます。
puts ENV['PATH']
システムのPATHを返します。したがって、プログラムnmap
が存在するかどうかを知りたい場合、これを行うことができます。
ENV['PATH'].split(':').each {|folder| puts File.exists?(folder+'/nmap')}
これは、ファイルが見つかった場合はtrue
を、そうでない場合はfalse
を出力します。
これが私が使用しているものです。これはプラットフォームに依存しません(File::PATH_SEPARATOR
は":"
Unixおよび";"
Windowsの場合、現在のプロセスの有効なユーザーによって実際に実行可能なプログラムファイルのみを検索し、プログラムが見つかるとすぐに終了します。
##
# Returns +true+ if the +program+ executable is found in the user's path.
def has_program?(program)
ENV['PATH'].split(File::PATH_SEPARATOR).any? do |directory|
File.executable?(File.join(directory, program.to_s))
end
end
which
がサイレントモードのフラグ-s
を取り、成功フラグのみを設定し、出力をリダイレクトする必要がないことを追加したいと思います。
私はこれを持っています:
def command?(name)
[name,
*ENV['PATH'].split(File::PATH_SEPARATOR).map {|p| File.join(p, name)}
].find {|f| File.executable?(f)}
end
コマンドだけでなくフルパスでも機能します:
irb(main):043:0> command?("/bin/bash")
=> "/bin/bash"
irb(main):044:0> command?("bash")
=> "/bin/bash"
irb(main):006:0> command?("bush")
=> nil
which_Ruby
というGEMがありましたが、これは純粋なRubyの実装でした。もう利用できません。
しかし、私はこれを見つけました pure-Rubyの代替実装 。
これは、 @ mislav's answer に基づく改良版です。これにより、あらゆるタイプのパス入力が可能になり、cmd.exe
は、Windowsで実行するファイルを選択します。
# which(cmd) :: string or nil
#
# Multi-platform implementation of "which".
# It may be used with UNIX-based and DOS-based platforms.
#
# The argument can not only be a simple command name but also a command path
# may it be relative or complete.
#
def which(cmd)
raise ArgumentError.new("Argument not a string: #{cmd.inspect}") unless cmd.is_a?(String)
return nil if cmd.empty?
case RbConfig::CONFIG['Host_os']
when /cygwin/
exts = nil
when /dos|mswin|^win|mingw|msys/
pathext = ENV['PATHEXT']
exts = pathext ? pathext.split(';').select{ |e| e[0] == '.' } : ['.com', '.exe', '.bat']
else
exts = nil
end
if cmd[File::SEPARATOR] or (File::ALT_SEPARATOR and cmd[File::ALT_SEPARATOR])
if exts
ext = File.extname(cmd)
if not ext.empty? and exts.any?{ |e| e.casecmp(ext).zero? } \
and File.file?(cmd) and File.executable?(cmd)
return File.absolute_path(cmd)
end
exts.each do |ext|
exe = "#{cmd}#{ext}"
return File.absolute_path(exe) if File.file?(exe) and File.executable?(exe)
end
else
return File.absolute_path(cmd) if File.file?(cmd) and File.executable?(cmd)
end
else
paths = ENV['PATH']
paths = paths ? paths.split(File::PATH_SEPARATOR).select{ |e| File.directory?(e) } : []
if exts
ext = File.extname(cmd)
has_valid_ext = (not ext.empty? and exts.any?{ |e| e.casecmp(ext).zero? })
paths.unshift('.').each do |path|
if has_valid_ext
exe = File.join(path, "#{cmd}")
return File.absolute_path(exe) if File.file?(exe) and File.executable?(exe)
end
exts.each do |ext|
exe = File.join(path, "#{cmd}#{ext}")
return File.absolute_path(exe) if File.file?(exe) and File.executable?(exe)
end
end
else
paths.each do |path|
exe = File.join(path, cmd)
return File.absolute_path(exe) if File.file?(exe) and File.executable?(exe)
end
end
end
nil
end
Linuxでは次を使用します。
exists = `which #{command}`.size.>(0)
残念ながら、which
はPOSIXコマンドではないため、Mac、BSDなどでは異なる動作をします(コマンドが見つからない場合はエラーをスローします)。たぶん、理想的な解決策は
`command -v #{command}`.size.>(0) # fails!: Ruby can't access built-in functions
しかし、これはRubyは組み込み関数にアクセスできないようです。しかしcommand -v
は、これを行うPOSIXの方法です。
Rogeriovlに基づくソリューションですが、存在テストではなく実行テストで機能を完了します。
def command_exists?(command)
ENV['PATH'].split(':').each {|folder| File.executable?(File.join(folder, command))}
end
UNIXでのみ機能します(Windowsは区切り文字としてコロンを使用しません)
#####################################################
# add methods to see if there's an executable that's executable
#####################################################
class File
class << self
###########################################
# exists and executable
###########################################
def cmd_executable?(cmd)
!ENV['PATH'].split(':').select { |f| executable?(join(f, cmd[/^[^ \n\r]*/])) }.empty?
end
end
end
jrubyの場合、mkmf
に依存するソリューションはC拡張があるため動作しない可能性があります。
jrubyの場合、パス上で何かが実行可能かどうかを確認する簡単な方法は次のとおりです。
main » unix_process = Java.lang.Runtime.getRuntime().exec("git status")
=> #<Java::JavaLang::UNIXProcess:0x64fa1a79>
main » unix_process.exitValue()
=> 0
main »
実行可能ファイルがない場合、実行時エラーが発生するため、実際の使用ではtry/catchブロックでこれを実行することをお勧めします。
これはrogeriopvlの答えの微調整であり、クロスプラットフォームになります。
require 'rbconfig'
def is_windows?
Config::CONFIG["Host_os"] =~ /mswin|mingw/
end
def exists_in_path?(file)
entries = ENV['PATH'].split(is_windows? ? ";" : ":")
entries.any? {|f| File.exists?("#{f}/#{file}")}
end