“which in ruby”: Checking if program exists in $PATH from ruby

后端 未结 16 1120
萌比男神i
萌比男神i 2020-12-07 12:15

my scripts rely heavily on external programs and scripts. I need to be sure that a program I need to call exists. Manually, I\'d check this using \'which\' in the commandlin

16条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-07 12:34

    This is an improved version based on @mislav's answer. This would allow any type of path input and strictly follows how cmd.exe chooses the file to execute in 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
    

提交回复
热议问题