"在红宝石中":检查来自ruby的$ PATH中是否存在程序

Yan*_*urm 76 ruby unix path

我的脚本严重依赖外部程序和脚本.我需要确保我需要调用的程序存在.手动,我会在命令行中使用"which"来检查.

有没有相当于File.exists?东西$PATH

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

谢谢!雅尼克


更新:这是我保留的解决方案:

 def command?(command)
       system("which #{ command} > /dev/null 2>&1")
 end
Run Code Online (Sandbox Code Playgroud)

更新2:有一些新的答案 - 至少其中一些提供了更好的解决方案.

更新3:ptools gem为File类添加了"which"方法.

mis*_*lav 118

真正的跨平台解决方案,在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
Run Code Online (Sandbox Code Playgroud)

这不使用主机操作系统嗅探,并且尊重$ PATHEXT,它列出了Windows上可执行文件的有效文件扩展名.

脱壳出来which的作品在许多系统上,但不是全部.

  • 应该使用`exe =#{path}#{File :: SEPARATOR}#{cmd}#{ext}` (4认同)

NAR*_*KOZ 78

使用stdlib中包含的find_executable方法mkmf.

require 'mkmf'

find_executable 'ruby'
#=> "/Users/narkoz/.rvm/rubies/ruby-2.0.0-p0/bin/ruby"

find_executable 'which-ruby'
#=> nil
Run Code Online (Sandbox Code Playgroud)

  • 调用mkmf会使用mkmf.log文件污染您的目录. (22认同)
  • 如果要避免创建物理日志文件,可以修补MakeMakefile记录器以将日志文件写入ruby等效的`/ dev/null`.请参阅此要点:https://gist.github.com/mnem/2540fece4ed9d3403b98 (6认同)
  • 要求"mkmf"通常是一个坏主意,并且被ruby开发人员建议(参见https://bugs.ruby-lang.org/issues/12370#note-4) - 它仅用于extconf. RB (6认同)
  • +1我认为这是最好的答案. (5认同)
  • Windows上唯一的轻微问题是,这将默认为构建您的ruby副本而不是本地列表的框中的可执行扩展名列表.`MakeMakefile :: CONFIG ["EXECUTABLE_EXTS"] = ENV ['PATHEXT'] .split(';').join('')`应该解决这个问题. (3认同)
  • 哦,确实是-这就是答案 (2认同)
  • 同样,'require'mkmf'`会通过其功能污染您的全局名称空间。在脚本中可能很好,但在更广泛的应用程序中却很糟糕。 (2认同)

blu*_*yed 16

def command?(name)
  `which #{name}`
  $?.success?
end
Run Code Online (Sandbox Code Playgroud)

最初取自hub,而type -t不是使用which(对于我来说,zsh和bash都失败了).

  • 在*nix平台上可以更广泛地使用,但是当找不到任何内容时,不会在所有平台上返回非零退出状态.`command -v`是posix标准,在posix平台上更可靠. (4认同)

Tod*_*obs 6

使用MakeMakefile#find_executable0并禁用Logging

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

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
Run Code Online (Sandbox Code Playgroud)

这使用MakeMakefile#find_executable调用的未记录的#find_executable0方法返回路径而不会使标准输出混乱.#which方法还会临时将mkmf日志文件重定向到/ dev/null,以防止使用"mkmf.log"或类似内容混乱当前工作目录.


rog*_*pvl 5

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

puts ENV['PATH']
Run Code Online (Sandbox Code Playgroud)

它将返回您系统上的PATH.因此,如果您想知道程序是否nmap存在,您可以这样做:

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

true如果找到文件或false其他方式,将打印.