section - "Which in ruby": verificando si el programa existe en $ PATH de ruby
wbr tag in html5 (16)
Use MakeMakefile # find_executable0 con Logging desactivado
Ya hay varias buenas respuestas, pero esto es lo que uso:
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
Esto utiliza el método # find_executable0 indocumentado invocado por MakeMakefile#find_executable para devolver la ruta sin saturar el resultado estándar. El método #which también redirige temporalmente el archivo de registro mkmf a / dev / null para evitar saturar el directorio de trabajo actual con "mkmf.log" o similar.
mis scripts dependen en gran medida de programas y scripts externos. Necesito estar seguro de que existe un programa que necesito llamar. Manualmente, verificaría esto usando ''which'' en la línea de comando.
¿Hay un equivalente a File.exists?
para cosas en $PATH
?
(Sí, supongo que podría analizar %x[which scriptINeedToRun]
pero eso no es súper elegante.
¡Gracias! yannick
ACTUALIZAR: esta es la solución que conservé:
def command?(command)
system("which #{ command} > /dev/null 2>&1")
end
ACTUALIZACIÓN 2: Han llegado algunas respuestas nuevas, al menos algunas ofrecen mejores soluciones.
Actualización 3: la gema de ptools ha agregado un método "que" a la clase Archivo.
En Linux utilizo:
exists = `which #{command}`.size.>(0)
Desafortunadamente, which
no es un comando POSIX y se comporta de manera diferente en Mac, BSD, etc. (es decir, arroja un error si el comando no se encuentra). Tal vez la solución ideal sería usar
`command -v #{command}`.size.>(0) # fails!: ruby can''t access built-in functions
Pero esto falla porque ruby parece no ser capaz de acceder a funciones incorporadas. Pero el command -v
sería la manera POSIX de hacer esto.
Esta es una versión mejorada basada en la respuesta de @ mislav . Esto permitiría cualquier tipo de entrada de ruta y sigue estrictamente cómo cmd.exe
elige el archivo para ejecutar en 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
Este es un ajuste de la respuesta de rogeriopvl, por lo que es multiplataforma:
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
Esto es lo que estoy usando. Esta es la plataforma neutral ( File::PATH_SEPARATOR
es ":"
en Unix y ";"
en Windows), solo busca los archivos de programa que en realidad son ejecutables por el usuario efectivo del proceso actual, y termina tan pronto como se encuentra el programa :
##
# 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
Hubo un GEM llamado which_ruby
que era un puro-Ruby que implementación. Ya no está disponible.
Sin embargo, encontré esta implementación alternativa pura de Ruby .
La verdadera solución multiplataforma funciona correctamente en 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
Esto no utiliza el rastreo del sistema operativo del host, y respeta $ PATHEXT que enumera las extensiones de archivo válidas para ejecutables en Windows.
Desgravación a la which
funciona en muchos sistemas, pero no en todos.
Me gustaría agregar eso which
toma las banderas -s
para el modo silencioso, que solo establece la bandera de éxito, eliminando la necesidad de redirigir la salida.
No es tan elegante, pero funciona :).
def cmdExists?(c)
system(c + " > /dev/null")
return false if $?.exitstatus == 127
true
end
Advertencia : ¡ NO es un consejo recomendado, peligroso !
Puede acceder a las variables de entorno del sistema con el hash ENV:
puts ENV[''PATH'']
Devolverá la RUTA en su sistema. Entonces, si quiere saber si el programa nmap
existe, puede hacer esto:
ENV[''PATH''].split('':'').each {|folder| puts File.exists?(folder+''/nmap'')}
Esto se imprimirá true
si el archivo fue encontrado o false
contrario.
Solución basada en rogeriovl, pero completa la función con la prueba de ejecución en lugar de la prueba de existencia.
def command_exists?(command)
ENV[''PATH''].split('':'').each {|folder| File.executable?(File.join(folder, command))}
end
Funcionará solo para UNIX (Windows no usa dos puntos como separador)
Tengo esto:
def command?(name)
[name,
*ENV[''PATH''].split(File::PATH_SEPARATOR).map {|p| File.join(p, name)}
].find {|f| File.executable?(f)}
end
funciona tanto para rutas completas como para comandos:
irb(main):043:0> command?("/bin/bash")
=> "/bin/bash"
irb(main):044:0> command?("bash")
=> "/bin/bash"
irb(main):006:0> command?("bush")
=> nil
Use el método find_executable
de mkmf
que se incluye en stdlib.
require ''mkmf''
find_executable ''ruby''
#=> "/Users/narkoz/.rvm/rubies/ruby-2.0.0-p0/bin/ruby"
find_executable ''which-ruby''
#=> nil
para jruby, cualquiera de las soluciones que dependen de mkmf
puede no funcionar, ya que tiene una extensión C.
para jruby, la siguiente es una forma fácil de verificar si algo es ejecutable en la ruta:
main » unix_process = java.lang.Runtime.getRuntime().exec("git status")
=> #<Java::JavaLang::UNIXProcess:0x64fa1a79>
main » unix_process.exitValue()
=> 0
main »
si el ejecutable no está allí, generará un error de tiempo de ejecución, por lo que es posible que desee hacer esto en un bloque try / catch en su uso real.
#####################################################
# 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 command?(name)
`which #{name}`
$?.success?
end
Inicialmente tomado del hub , que usó el type -t
lugar del which
aunque (y que falló tanto para zsh como para bash para mí).