我的脚本在很大程度上依赖于外部程序和脚本。我需要确保我需要调用的程序存在。手动地,我会在命令行中使用“哪个”来检查。
是否有等同File.exists?
于$PATH
?
(是的,我想我可以解析 %x[which scriptINeedToRun]
但这不是超级优雅。
谢谢!扬尼克
更新:这是我保留的解决方案:
def command?(command)
system("which #{ command} > /dev/null 2>&1")
end
我的脚本在很大程度上依赖于外部程序和脚本。我需要确保我需要调用的程序存在。手动地,我会在命令行中使用“哪个”来检查。
是否有等同File.exists?
于$PATH
?
(是的,我想我可以解析 %x[which scriptINeedToRun]
但这不是超级优雅。
谢谢!扬尼克
更新:这是我保留的解决方案:
def command?(command)
system("which #{ command} > /dev/null 2>&1")
end
which
存在命令的UNIX系统上有效。这不包括Windows和某些其他系统。请记住,Windows在Ruby开发人员中仍然大量使用。请参阅我的解决方案以获取真正的跨平台命令。
find_executable
ptools
宝石对我来说非常完美!
Answers:
真正的跨平台解决方案,在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 do |ext|
exe = File.join(path, "#{cmd}#{ext}")
return exe if File.executable?(exe) && !File.directory?(exe)
end
end
nil
end
这不使用主机操作系统嗅探,而是遵守$ PATHEXT,它列出了Windows上可执行文件的有效文件扩展名。
脱壳出来which
的作品在许多系统上,但不是全部。
!File.directory?(exe)
代替File.file?(exe)
?
使用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
MakeMakefile::CONFIG["EXECUTABLE_EXTS"] = ENV['PATHEXT'].split(';').join(' ')
应该解决这个问题。
/dev/null
如果要避免创建物理日志文件)。有关示例,请参见以下摘要
mkmf
通常不是一个好主意,并且被ruby开发人员建议(请参见bugs.ruby-lang.org/issues/12370#note-4)-它仅用于extconf.rb
require 'mkmf'
用其功能污染全局名称空间。在脚本中可能很好,但在更广泛的应用程序中却很糟糕。
def command?(name)
`which #{name}`
$?.success?
end
最初是从hub那里获取的,它使用了type -t
替代方法(which
但对我来说zsh和bash都失败了)。
command -v
是posix标准,在posix平台上更可靠。
which #{name}.empty?
?
> which foo
返回no foo in /opt/local/bin /opt/local/sbin /usr/bin /usr/sbin
已经有很多好的答案,但是这是我使用的:
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方法来返回路径,而不会混淆标准输出。#which方法还将临时将mkmf日志文件重定向到/ dev / null,以防止使用“ mkmf.log”或类似内容使当前工作目录混乱。
mkmf
与ffi
基于-gem发生冲突。这确实限制了该解决方案的实用性。
您可以使用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
有一个GEM被称为which_ruby
纯Ruby实现。它不再可用。
但是,我发现了这种纯Ruby替代实现。
我想添加一个which
带有-s
静音模式标志的标志,该标志仅设置成功标志,而无需重定向输出。
which
上,不接受-s标志,该标志是否在某处指定?
man which
告诉我有关我的系统的信息。但是,我的手册页说:“某些shell可能会提供一个与此命令实用程序相似或相同的内置命令。请查阅buildin(1)手册页。” YMMV。
这是基于@mislav的答案的改进版本。这将允许任何类型的路径输入,并且严格遵循如何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
我有这个:
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
在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的方法。
sh -c 'command -v #command'
,您就可以做到。我试图在此处编辑您的答案以达到这种效果,但被拒绝了,因为显然我在“更改您的意思”。
which #{command}
exist = .size。>(0)不幸的是,which
它不是POSIX命令,因此在Mac,BSD等设备上的行为有所不同(即,如果找不到该命令,则会引发错误)。理想的解决方案是使用 sh -c 'command -v #{command}'
.size。>(0)这sh -c
是必需的,因为否则ruby将无法访问内置函数。但这command -v
将是POSIX的方法。
基于rogeriovl的解决方案,但具有执行测试而非存在测试的完整功能。
def command_exists?(command)
ENV['PATH'].split(':').each {|folder| File.executable?(File.join(folder, command))}
end
仅适用于UNIX(Windows不使用冒号作为分隔符)
对于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块中执行此操作。
#####################################################
# 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
警告:不建议这样做,危险的建议!
cmdExists?('rm -rf ~')
。另外,ruby约定是命名方法,例如cmd_exists?
which
如果该命令command
不存在,则该方法中的命令command将返回1;如果该命令存在,则将返回0command
。因此,要使该方法起作用,您应该将127替换为1