“在ruby”:检查程序是否存在于$ PATH从ruby

我的脚本严重依赖于外部程序和脚本。 我需要确定我需要调用的程序存在。 手动,我会检查这在命令行中使用“哪个”。

有一个相当于File.exists? 对于$PATH东西?

(是的,我想我可以parsing%x[which scriptINeedToRun]但这不是超级优雅。

谢谢! 雅尼克


更新:这是我保留的解决scheme:

  def command?(command) system("which #{ command} > /dev/null 2>&1") end 

更新2:一些新的答案已经进来 – 至less有一些提供更好的解决scheme。

更新3: ptools gem已经为File类添加了“which”方法。

真正的跨平台解决scheme,在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 

这不使用主机操作系统嗅探,而是考虑$ PATHEXT,它列出了Windows上可执行文件的有效文件扩展名。

在许多系统上运行,但不是全部。

使用包含在stdlib中的find_executable方法。

 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 

最初从集线器 ,其中使用type -t而不是(尽pipe这对我来说zsh和bash都失败了)。

您可以使用ENV哈希访问系统环境variables:

 puts ENV['PATH'] 

它将返回您的系统上的PATH。 所以如果你想知道程序nmap存在,你可以这样做:

 ENV['PATH'].split(':').each {|folder| puts File.exists?(folder+'/nmap')} 

如果find文件,这将打印为true ,否则打印为false

logging禁用时使用MakeMakefile#find_executable0

已经有很多好的答案,但是这里是我使用的:

 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 

这使用MakeMakefile#find_executable调用的未公开#find_executable0方法返回path,而不会混乱标准输出。 #which方法还会暂时将mkmf日志文件redirect到/ dev / null,以防止使用“mkmf.log”或类似方法混淆当前工作目录。

这是我正在使用的。 这是平台中立的( File::PATH_SEPARATOR在Unix上是":" ,在Windows上是":" ";" ),只查找当前进程的有效用户可以执行的程序文件,只要程序find就立即终止:

 ## # 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采取静音模式的标志,它只设置成功标志,消除了redirect输出的需要。

这是基于@ mislav的答案的改进版本。 这将允许任何types的pathinput,并严格遵循cmd.exe如何select文件在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 

有一个叫做which_ruby的GEM,是一个纯粹的Ruby实现。 已经不存在了

但是,我发现这个纯粹的Ruby替代实现 。

在Linux上我使用:

 exists = `which #{command}`.size.>(0) 

不幸的是, which不是一个POSIX命令,所以在Mac,BSD等上的行为不同(即,如果找不到命令,则会引发错误)。 也许理想的解决scheme是使用

 `command -v #{command}`.size.>(0) # fails!: ruby can't access built-in functions 

但是这样做是因为ruby似乎无法访问内置函数。 但command -v将是POSIX的方式来做到这一点。

基于rogeriovl的解决scheme,但完整的function与执行testing,而不是存在testing。

 def command_exists?(command) ENV['PATH'].split(':').each {|folder| File.executable?(File.join(folder, command))} end 

将只适用于UNIX(Windows不使用冒号作为分隔符)

我有这个:

 def command?(name) [name, *ENV['PATH'].split(File::PATH_SEPARATOR).map {|p| File.join(p, name)} ].find {|f| File.executable?(f)} end 

适用于完整path以及命令:

 irb(main):043:0> command?("/bin/bash") => "/bin/bash" irb(main):044:0> command?("bash") => "/bin/bash" irb(main):006:0> command?("bush") => nil 

这是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 

对于jruby而言,任何依赖于mkmf的解决scheme可能无法正常工作,因为它具有C扩展名。

对于jruby,以下是一个简单的方法来检查path上是否有可执行的内容:

 main » unix_process = java.lang.Runtime.getRuntime().exec("git status") => #<Java::JavaLang::UNIXProcess:0x64fa1a79> main » unix_process.exitValue() => 0 main » 

如果可执行文件不在那里,会引发一个运行时错误,所以你可能想在你的实际使用的try / catch块中做这个。

 ##################################################### # 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 

没有这么多的优雅,但它的作品:)。

 def cmdExists?(c) system(c + " > /dev/null") return false if $?.exitstatus == 127 true end 

警告 :这是build议的, 危险的build议!