mes scripts reposent largement sur des programmes et des scripts externes. Je dois être sûr qu’un programme que je dois appeler existe. Manuellement, je vérifierais ceci en utilisant ‘what’ dans la ligne de commande.
Y a-t-il un équivalent à File.exists?
pour des choses dans $PATH
?
(oui je suppose que je pourrais parsingr %x[which scriptINeedToRun]
mais ce n’est pas super élégant.
Merci! yannick
MISE À JOUR: Voici la solution que j’ai retenue:
def command?(command) system("which #{ command} > /dev/null 2>&1") end
Véritable solution multi-plateforme, 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 reniflage de l’OS hôte et respecte $ PATHEXT qui répertorie les extensions de fichier valides pour les exécutables sous Windows.
Shelling à which
fonctionne sur de nombreux systèmes mais pas tous.
Utilisez la méthode find_executable
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 le type -t
au lieu de which
(et qui a échoué pour zsh et bash pour moi).
Vous pouvez accéder aux variables d’environnement du système avec le hachage ENV:
puts ENV['PATH']
Il renverra le PATH sur votre système. Donc, si vous voulez savoir si le programme nmap
existe, vous pouvez le faire:
ENV['PATH'].split(':').each {|folder| puts File.exists?(folder+'/nmap')}
Cela affichera true
si le fichier a été trouvé ou false
sinon.
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 Ssortingng, 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
Cela utilise la méthode non documentée # find_executable0 appelée par MakeMakefile # find_executable pour renvoyer le chemin sans encombrer la sortie standard. La méthode #which redirige aussi temporairement le fichier journal mkmf vers / dev / null pour éviter d’encombrer le répertoire de travail actuel avec “mkmf.log” ou similaire.
Voici ce que j’utilise. Ceci est neutre pour la plate-forme ( 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
Je voudrais append ce which
prend le drapeau -s
pour le mode silencieux, qui ne définit que le drapeau de succès, ce qui supprime la nécessité de redirect la sortie.
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 suit ssortingctement comment cmd.exe
choisit le fichier à exécuter dans Windows.
# which(cmd) :: ssortingng 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 ssortingng: #{cmd.inspect}") unless cmd.is_a?(Ssortingng) 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
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 une implémentation pure-Ruby. Il n’est plus disponible.
Cependant, j’ai trouvé cette implémentation alternative pure-Ruby .
Sur Linux, j’utilise:
exists = `which #{command}`.size.>(0)
Malheureusement, which
n’est pas une commande POSIX et se comporte donc différemment sur Mac, BSD, etc. (c.-à-d. Génère une erreur si la commande est introuvable). 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 parce que ruby ne semble pas capable d’accéder aux fonctions intégrées. Mais command -v
serait la manière 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 pour UNIX (Windows n’utilise pas les deux points comme séparateur)
Ceci est un tweak de la réponse de rogeriopvl, ce qui rend la plate-forme croisée:
require 'rbconfig' def is_windows? Config::CONFIG["host_os"] =~ /mswin|mingw/ end def exists_in_path?(file) ensortinges = ENV['PATH'].split(is_windows? ? ";" : ":") ensortinges.any? {|f| File.exists?("#{f}/#{file}")} end
pour jruby, toutes les solutions qui dépendent de mkmf
peuvent ne pas fonctionner, car elles ont une extension C.
pour jruby, voici un moyen facile de vérifier si quelque chose est exécutable sur le chemin:
main » unix_process = java.lang.Runtime.getRuntime().exec("git status") => # main » unix_process.exitValue() => 0 main »
Si l’exécutable n’est pas là, il générera une erreur d’exécution. Vous pouvez donc le faire dans un bloc try / catch dans votre utilisation actuelle.
##################################################### # 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
Pas tellement élégant mais ça marche :).
def cmdExists?(c) system(c + " > /dev/null") return false if $?.exitstatus == 127 true end
Attention : Ceci n’est PAS recommandé, conseil dangereux !