Meine Skripte stützen sich stark auf externe Programme und Skripte. Ich muss sicher sein, dass ein Programm vorhanden ist, das ich aufrufen muss. Manuell würde ich dies mit 'which' in der Kommandozeile überprüfen.
Gibt es ein Äquivalent zu File.exists?
für Dinge in $PATH
?
(Ja, ich denke ich könnte analysieren, %x[which scriptINeedToRun]
aber das ist nicht super elegant.
Vielen Dank! Yannick
UPDATE: Hier ist die Lösung, die ich beibehalten habe:
def command?(command)
system("which #{ command} > /dev/null 2>&1")
end
which
befehl in der Methode gibt entweder 1 zurück, wenn der Befehlcommand
nicht vorhanden ist, oder 0, wenn der Befehlcommand
vorhanden ist. Damit die Methode funktioniert, sollten Sie 127 durch 1 ersetzenwhich
vorhanden ist. Dies schließt Windows und einige andere Systeme aus. Bitte denken Sie daran, dass Windows unter Ruby-Entwicklern immer noch stark genutzt wird. Siehe meine Lösung für einen echten plattformübergreifenden Befehl.find_executable
ptools
gem funktionierte perfekt für mich!Antworten:
Echte plattformübergreifende Lösung, funktioniert unter Windows ordnungsgemäß:
# 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
Dies verwendet kein Host-Betriebssystem-Sniffing und respektiert $ PATHEXT, das gültige Dateierweiterungen für ausführbare Dateien unter Windows auflistet.
Shelling out
which
funktioniert auf vielen Systemen, aber nicht auf allen.quelle
cmd
(/bin/sh
oder..\foo
) enthalten ist.!File.directory?(exe)
stattFile.file?(exe)
?Verwenden Sie die
find_executable
Methode, vonmkmf
der aus stdlib enthalten ist.require 'mkmf' find_executable 'ruby' #=> "/Users/narkoz/.rvm/rubies/ruby-2.0.0-p0/bin/ruby" find_executable 'which-ruby' #=> nil
quelle
MakeMakefile::CONFIG["EXECUTABLE_EXTS"] = ENV['PATHEXT'].split(';').join(' ')
sollte das beheben./dev/null
wenn Sie das Erstellen physischer Protokolldateien vermeiden möchten. In dieser Übersicht finden Sie ein Beispiel: gist.github.com/mnem/2540fece4ed9d3403b98mkmf
ist im Allgemeinen eine schlechte Idee und wird von Ruby-Entwicklern abgeraten (siehe bugs.ruby-lang.org/issues/12370#note-4 ) - es ist nur für die Verwendung in extconf.rbrequire 'mkmf'
verpestet Ihren globalen Namensraum mit seinen Funktionen. In einem Skript ist es wahrscheinlich in Ordnung, in einer breiteren App jedoch eine schreckliche Übung.def command?(name) `which #{name}` $?.success? end
Ursprünglich vom Hub genommen , der
type -t
stattdessen verwendet wurdewhich
(und der für mich sowohl für zsh als auch für bash fehlgeschlagen ist).quelle
command -v
ist der Posix-Standard und auf Posix-Plattformen zuverlässiger.which #{name}.empty?
?> which foo
zurückno foo in /opt/local/bin /opt/local/sbin /usr/bin /usr/sbin
Verwenden Sie MakeMakefile # find_executable0 mit deaktivierter Protokollierung
Es gibt bereits eine Reihe guter Antworten, aber ich verwende Folgendes:
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
Dies verwendet die undokumentierte Methode # find_executable0 , die von MakeMakefile # find_executable aufgerufen wird , um den Pfad zurückzugeben, ohne die Standardausgabe zu überladen . Die Methode #which leitet die mkmf-Protokolldatei auch vorübergehend nach / dev / null um, um zu verhindern, dass das aktuelle Arbeitsverzeichnis mit "mkmf.log" oder ähnlichem überfüllt ist.
quelle
mkmf
es beiffi
einigen Methodendefinitionen (von denen ich annehme, dass beide Edelsteine im Root-Namespace definiert sind) zu Konflikten mit gem-basierten Gems kommt. Dies schränkt den Nutzen der Lösung ein.Sie können mit dem ENV-Hash auf Systemumgebungsvariablen zugreifen:
puts ENV['PATH']
Der PATH wird auf Ihrem System zurückgegeben. Wenn Sie also wissen möchten, ob ein Programm
nmap
vorhanden ist, können Sie dies tun:ENV['PATH'].split(':').each {|folder| puts File.exists?(folder+'/nmap')}
Dies wird gedruckt,
true
wenn eine Datei gefunden wurde oderfalse
nicht.quelle
Hier ist was ich benutze. Dies ist plattformneutral (
File::PATH_SEPARATOR
ist":"
auf Unix und";"
Windows), sieht nur für Programmdateien , die tatsächlich durch die effektiven Benutzer des aktuellen Prozesses ausgeführt werden kann , und endet, sobald das Programm gefunden wird:## # 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
quelle
Es wurde ein Juwel gerufen
which_ruby
Pure-Ruby, dessen Implementierung. Es ist nicht mehr verfügbar.Ich fand jedoch diese reine Ruby-Alternative .
quelle
Ich möchte hinzufügen, dass
which
das Flag-s
für den stillen Modus verwendet wird, wodurch nur das Erfolgsflag gesetzt wird, sodass die Ausgabe nicht mehr umgeleitet werden muss.quelle
which
Akzeptiert auf meinem System kein -s-Flag, ist das irgendwo angegeben?man which
erzählte mir von meinem System. Auf meiner Manpage heißt es jedoch: "Einige Shells enthalten möglicherweise einen integrierten Befehl, der diesem Dienstprogramm ähnlich oder identisch ist. Lesen Sie die integrierte Handbuchseite (1)." YMMV.Dies ist eine verbesserte Version, die auf der Antwort von @ mislav basiert . Dies würde jede Art von Pfadeingabe ermöglichen und folgt genau der
cmd.exe
Auswahl der Datei, die in Windows ausgeführt werden soll.# 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
quelle
Ich habe das:
def command?(name) [name, *ENV['PATH'].split(File::PATH_SEPARATOR).map {|p| File.join(p, name)} ].find {|f| File.executable?(f)} end
funktioniert für vollständige Pfade sowie Befehle:
irb(main):043:0> command?("/bin/bash") => "/bin/bash" irb(main):044:0> command?("bash") => "/bin/bash" irb(main):006:0> command?("bush") => nil
quelle
Unter Linux benutze ich:
exists = `which #{command}`.size.>(0)
Leider
which
handelt es sich nicht um einen POSIX-Befehl und verhält sich daher auf Mac, BSD usw. anders (dh es wird ein Fehler ausgegeben, wenn der Befehl nicht gefunden wird). Vielleicht wäre die ideale Lösung zu verwenden`command -v #{command}`.size.>(0) # fails!: ruby can't access built-in functions
Dies schlägt jedoch fehl, da Ruby anscheinend nicht in der Lage ist, auf integrierte Funktionen zuzugreifen. Wäre
command -v
aber der POSIX-Weg, dies zu tun.quelle
sh -c 'command -v #command'
, und Sie haben es. Ich habe versucht, Ihre Antwort hier zu diesem Zweck zu bearbeiten, aber sie wurde abgelehnt, weil ich anscheinend "Ihre Bedeutung geändert" habe.which #{command}
existes = .size.> (0) Leiderwhich
handelt es sich nicht um einen POSIX-Befehl und verhält sich daher auf Mac, BSD usw. anders (dh es wird ein Fehler ausgegeben , wenn der Befehl nicht gefunden wird). Die ideale Lösung ist die Verwendung vonsh -c 'command -v #{command}'
.size.> (0) Diessh -c
ist erforderlich, da Ruby sonst nicht auf integrierte Funktionen zugreifen kann. Abercommand -v
wäre der POSIX-Weg, dies zu tun.Lösung basierend auf Rogeriovl, aber vollständige Funktion mit Ausführungstest statt Existenztest.
def command_exists?(command) ENV['PATH'].split(':').each {|folder| File.executable?(File.join(folder, command))} end
Funktioniert nur unter UNIX (Windows verwendet keinen Doppelpunkt als Trennzeichen)
quelle
Dies ist eine Optimierung der Antwort von Rogeriopvl, die es plattformübergreifend macht:
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
quelle
für jruby eine der Lösungen, die davon abhängen
mkmf
funktioniert möglicherweise keine , da sie eine C-Erweiterung hat.Für jruby ist Folgendes eine einfache Möglichkeit, um zu überprüfen, ob auf dem Pfad etwas ausführbar ist:
main » unix_process = java.lang.Runtime.getRuntime().exec("git status") => #<Java::JavaLang::UNIXProcess:0x64fa1a79> main » unix_process.exitValue() => 0 main »
Wenn die ausführbare Datei nicht vorhanden ist, wird ein Laufzeitfehler ausgelöst. Daher möchten Sie dies möglicherweise in einem Try / Catch-Block in Ihrer tatsächlichen Verwendung tun.
quelle
##################################################### # 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
quelle
Nicht so elegant, aber es funktioniert :).
def cmdExists?(c) system(c + " > /dev/null") return false if $?.exitstatus == 127 true end
Warnung : Dies wird NICHT empfohlen, gefährlicher Rat!
quelle
cmdExists?('rm -rf ~')
. Auch Ruby Konvention ist es, Methoden wiecmd_exists?