Programing

"which in ruby": 프로그램이 ruby에서 $ PATH에 있는지 확인

lottogame 2020. 10. 18. 08:19
반응형

"which in ruby": 프로그램이 ruby에서 $ PATH에 있는지 확인


내 스크립트는 외부 프로그램과 스크립트에 크게 의존합니다. 호출해야하는 프로그램이 있는지 확인해야합니다. 수동으로 명령 줄에서 'which'를 사용하여 확인합니다.

에 대한 것과 동등한 File.exists?것이 $PATH있습니까?

(예, 구문 분석 할 수 있다고 생각 %x[which scriptINeedToRun]하지만 매우 우아하지는 않습니다.

감사! Yannick


업데이트 : 내가 유지 한 솔루션은 다음과 같습니다.

 def command?(command)
       system("which #{ command} > /dev/null 2>&1")
 end

업데이트 2 : 몇 가지 새로운 답변이 나왔습니다. 적어도 이들 중 일부는 더 나은 솔루션을 제공합니다.

업데이트 3 : ptools gem 은 File 클래스에 "which"메소드를 추가했습니다.


진정한 크로스 플랫폼 솔루션은 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

이것은 호스트 OS 스니핑을 사용하지 않으며 Windows에서 실행 파일의 유효한 파일 확장자를 나열하는 $ PATHEXT를 존중합니다.

which많은 시스템 에서 작동하지만 전부는 아닙니다.


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

def command?(name)
  `which #{name}`
  $?.success?
end

처음에는 대신 사용 하는 hub 에서 가져 왔습니다 (그리고 나를 위해 zsh와 bash 모두 실패했습니다).type -twhich


로깅이 비활성화 된 상태에서 MakeMakefile # find_executable0 사용

이미 많은 좋은 답변이 있지만 여기에 내가 사용하는 것이 있습니다.

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"또는 이와 유사한 것으로 복잡 해지는 것을 방지합니다.


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

which_ruby순수 Ruby 구현 이라는 GEM이있었습니다 . 더 이상 사용할 수 없습니다.

그러나 나는이 순수한 루비 대체 구현을 발견했습니다 .


성공 플래그 만 설정하는 자동 모드에 which대한 플래그 -s를 사용하여 출력을 리디렉션 할 필요가 없도록 추가하고 싶습니다 .


이것은 @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)

불행히도은 whichPOSIX 명령이 아니므로 Mac, BSD 등에서 다르게 작동합니다 (예 : 명령을 찾을 수없는 경우 오류 발생). 아마도 이상적인 해결책은

`command -v #{command}`.size.>(0)  # fails!: ruby can't access built-in functions

그러나 이것은 루비가 내장 함수에 접근 할 수없는 것처럼 보이기 때문에 실패합니다. 그러나 command -v이것을 수행하는 POSIX 방법이 될 것입니다.


Solution based on rogeriovl, but complete function with execution test rather than existence test.

def command_exists?(command)
  ENV['PATH'].split(':').each {|folder| File.executable?(File.join(folder, command))}
end

Will work only for UNIX (Windows does not use colon as a separator)


This is a tweak of rogeriopvl's answer, making it cross platform:

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

for jruby, any of the solutions that depend on mkmf may not work, as it has a C extension.

for jruby, the following is an easy way to check if something is executable on the path:

main » unix_process = java.lang.Runtime.getRuntime().exec("git status")
=> #<Java::JavaLang::UNIXProcess:0x64fa1a79>
main » unix_process.exitValue()
=> 0
main »

if the executable isn't there, it will raise a runtime error, so you may want to do this in a try/catch block in your actual usage.


#####################################################
# 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

Not so much elegant but it works :).

def cmdExists?(c)
  system(c + " > /dev/null")
  return false if $?.exitstatus == 127
  true
end

Warning: This is NOT recommended, dangerous advice!

참고URL : https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby

반응형