mes scripts reposent largement sur des programmes et des scripts externes ... Je dois être sûr qu'un programme à appeler existe. Manuellement, je vérifierais ceci en utilisant 'qui' dans la ligne de commande.
Existe-t-il un équivalent de File.exists?
pour les éléments de $PATH
?
(oui je suppose que je pourrais analyser %x[which scriptINeedToRun]
mais ce n'est pas très élégant.
Merci! Yannick
UPDATE: Voici la solution que j'ai retenue:
def command?(command)
system("which #{ command} > /dev/null 2>&1")
end
Véritable solution multiplateforme, fonctionne correctement sous 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
Cela n'utilise pas le reniflement de l'OS hôte et respecte $ PATHEXT, qui répertorie les extensions de fichier valides pour les exécutables sous Windows.
Décaler à which
fonctionne sur de nombreux systèmes mais pas sur tous.
Utilisez find_executable
méthode de mkmf
qui est incluse dans stdlib.
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
Initialement pris à partir de hub , qui utilisait type -t
au lieu de which
cependant (et qui a échoué pour zsh et bash pour moi).
Il y a déjà un certain nombre de bonnes réponses, mais voici ce que j'utilise:
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
Ceci utilise la méthode non documentée # find_executable0 invoquée par MakeMakefile # find_executable pour renvoyer le chemin sans encombrer la sortie standard. La méthode #which redirige également temporairement le fichier journal mkmf vers / dev/null afin d'éviter d'encombrer le répertoire de travail actuel avec "mkmf.log" ou similaire.
Vous pouvez accéder aux variables d'environnement système avec le hachage ENV:
puts ENV['PATH']
Il retournera le PATH sur votre système. Donc, si vous voulez savoir si le programme nmap
existe, vous pouvez faire ceci:
ENV['PATH'].split(':').each {|folder| puts File.exists?(folder+'/nmap')}
Ceci imprimera true
si le fichier a été trouvé ou false
sinon.
J'aimerais ajouter que which
prend l'indicateur -s
pour le mode silencieux, qui ne définit que l'indicateur de succès, ce qui supprime la nécessité de rediriger la sortie.
J'ai ceci:
def command?(name)
[name,
*ENV['PATH'].split(File::PATH_SEPARATOR).map {|p| File.join(p, name)}
].find {|f| File.executable?(f)}
end
fonctionne pour les chemins complets ainsi que les commandes:
irb(main):043:0> command?("/bin/bash")
=> "/bin/bash"
irb(main):044:0> command?("bash")
=> "/bin/bash"
irb(main):006:0> command?("bush")
=> nil
Il y avait un GEM appelé which_Ruby
qui était un pur Ruby dont la mise en œuvre ..__ n'est plus disponible.
Cependant, j'ai trouvé cette implémentation alternative pure-Ruby .
Voici ce que j'utilise. Ceci est neutre (File::PATH_SEPARATOR
est ":"
sous Unix et ";"
sous Windows), recherche uniquement les fichiers de programme réellement exécutables par l'utilisateur effectif du processus en cours et se termine dès que le programme est trouvé:
##
# 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
Ceci est une version améliorée basée sur La réponse de @ mislav . Cela permettrait n'importe quel type d'entrée de chemin et suivrait rigoureusement la façon dont cmd.exe
choisit le fichier à exécuter dans 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
Sur Linux j'utilise:
exists = `which #{command}`.size.>(0)
Malheureusement, which
n’est pas une commande POSIX et se comporte donc différemment sous Mac, BSD, etc. (c’est-à-dire qu’il génère une erreur si la commande n’est pas trouvée). Peut-être que la solution idéale serait d'utiliser
`command -v #{command}`.size.>(0) # fails!: Ruby can't access built-in functions
Mais cela échoue car Ruby semble ne pas être capable d'accéder aux fonctions intégrées. Mais command -v
serait le moyen POSIX de le faire.
Solution basée sur rogeriovl, mais fonction complète avec test d'exécution plutôt que test d'existence.
def command_exists?(command)
ENV['PATH'].split(':').each {|folder| File.executable?(File.join(folder, command))}
end
Ne fonctionnera que sous UNIX (Windows n'utilise pas les deux points comme séparateur)
#####################################################
# 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
pour jruby, l’une des solutions dépendant de mkmf
risque de ne pas fonctionner car elle a une extension C.
pour jruby, voici un moyen simple de vérifier si quelque chose est exécutable sur le chemin:
main » unix_process = Java.lang.Runtime.getRuntime().exec("git status")
=> #<Java::JavaLang::UNIXProcess:0x64fa1a79>
main » unix_process.exitValue()
=> 0
main »
si l'exécutable n'est pas présent, une erreur d'exécution sera générée. Vous souhaiterez peut-être le faire dans un bloc try/catch dans votre utilisation réelle.
Ceci est un Tweak de la réponse de rogeriopvl, ce qui la rend multi-plateforme:
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