Class: EasySH

Inherits:
Struct
  • Object
show all
Includes:
Enumerable
Defined in:
lib/easysh.rb

Overview

EasySH examples:

sh = EasySH.new

# basic usage
puts sh.ls
puts sh['/bin/ls']

# command parameters
puts sh.ls['/bin']._l
puts sh.ls._l '/bin'
puts sh.ls('/bin', :l, :color => :always)
puts sh['/bin/ls', '-l', :color => :always]

# enumerable
sh.ls.max
sh.ls.sort
sh.ls.chars.to_a.sample(5)
sh.cat('/dev/urandom').bytes.first(10)
sh.ls._l.map{|l| l.split}
sh.ps._e._o('euser,comm').map(&:split).group_by(&:first)

# chaining commands
sudo = sh.sudo
tail = sh.tail
sudo[tail._f '/var/log/everything.log'].lines { |l| puts l.upcase }
sudo.tail._f '/var/log/everything.log' do |l| puts l.upcase end

lab = sh.ssh['lab'] # or, sh.ssh.lab
puts lab.ls._l '/bin', color: :always

# redirects
puts sh.echo('hello') > '/tmp/test'
puts sh.echo 'hello', 1 => '/tmp/stdout', 2 => '/tmp/stderr'
puts sh.cat < '/tmp/test'
puts sh.cat 0 => '/tmp/fffff'

# pipes
puts sh.man('ls') | sh.tail(n: 30) | sh.head(:n, 4)

grep   = sh['grep']
filter = grep['problem'] | grep._v['bugs']
puts sh.man.ls | filter

kat = sh.cat
puts kat['/tmp/foo'] | (kat | kat | kat.|(kat) | (kat | kat) | (kat | kat))

# exit status
p = sh.which('bash')
puts p
p.exitstatus        # => #<Process::Status: pid 5931 exit 0>
p = sh.which.nonexists
puts p
p.exitstatus        # => #<Process::Status: pid 6156 exit 1>

# instant mode
# tired with 'puts' and 'to_s' in REPL? just set instant = true
# [2] pry(main)> sh.instant = false; sh.uptime
# => #<EasySH: uptime>
# [3] pry(main)> sh.instant = true; sh.uptime
# =>  22:14:23 up 1 day,  4:02, 12 users,  load average: 0.69, 0.65, 0.67
# [4] pry(main)> sh = EasySH.instant; sh.uname
# =>  Linux

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object Also known as: call, []

:no-doc:



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/easysh.rb', line 72

def method_missing name, *args, &block # :no-doc:
  begin
    return super(name, *args, &block)
  rescue NoMethodError, ArgumentError => ex
    # continue
  end

  r = if name.is_a? EasySH
        self.class.new [*cmd, *name.cmd], Hash[*opt, *name.opt], chain, instant
      else
        args = [name.to_s.gsub(/^_+/) {|s| '-' * s.size}, *args]
        *args, opt = *args if args.last.is_a?(Hash) && args.last.keys.find{|k| k.is_a? Integer}
        args = args.map do |a|
          case a
          when Symbol
            "-#{a.length > 1 ? '-' : ''}#{a}"
          when Hash
            a.map { |k,v| k.length > 1 ? "--#{k}=#{v}" : "-#{k} #{v}" }
          else
            a.to_s
          end
        end.flatten
        self.class.new [*cmd, *args], Hash[[*self.opt, *opt]], chain, instant
      end
  block ? r.each(&block) : r
end

Instance Attribute Details

#chainObject

Returns the value of attribute chain

Returns:

  • (Object)

    the current value of chain



67
68
69
# File 'lib/easysh.rb', line 67

def chain
  @chain
end

#cmdObject

Returns the value of attribute cmd

Returns:

  • (Object)

    the current value of cmd



67
68
69
# File 'lib/easysh.rb', line 67

def cmd
  @cmd
end

#exitstatusObject (readonly)

Returns the value of attribute exitstatus.



70
71
72
# File 'lib/easysh.rb', line 70

def exitstatus
  @exitstatus
end

#instantObject

Returns the value of attribute instant

Returns:

  • (Object)

    the current value of instant



67
68
69
# File 'lib/easysh.rb', line 67

def instant
  @instant
end

#optObject

Returns the value of attribute opt

Returns:

  • (Object)

    the current value of opt



67
68
69
# File 'lib/easysh.rb', line 67

def opt
  @opt
end

Class Method Details

.instantObject



181
182
183
# File 'lib/easysh.rb', line 181

def self.instant
  new(nil, {}, [], true)
end

Instance Method Details

#<(path) ⇒ Object



111
# File 'lib/easysh.rb', line 111

def < path; self.opt[0] = path; self; end

#>(path) ⇒ Object



112
# File 'lib/easysh.rb', line 112

def > path; self.opt[1] = path; self; end

#each_byteObject Also known as: bytes



161
162
163
164
# File 'lib/easysh.rb', line 161

def each_byte
  return to_enum(:each_byte) unless block_given?
  to_io { |i| while b = i.getbyte; yield b; end }
end

#each_charObject Also known as: chars



156
157
158
159
# File 'lib/easysh.rb', line 156

def each_char
  return to_enum(:each_char) unless block_given?
  to_io { |i| while c = i.getc; yield c; end }
end

#each_lineObject Also known as: lines, each



151
152
153
154
# File 'lib/easysh.rb', line 151

def each_line
  return to_enum(:each_line) unless block_given?
  to_io { |i| while l = i.gets; yield l.chomp; end }
end

#inspectObject



102
103
104
# File 'lib/easysh.rb', line 102

def inspect
  instant ? to_s : "#<#{self.class}: #{([*chain, [cmd]]).map(&:first).map {|c| c && c.join(' ')}.compact.join(' | ')}>"
end

#pretty_print(q) ⇒ Object



177
178
179
# File 'lib/easysh.rb', line 177

def pretty_print(q)
  q.text self.inspect
end

#to_aObject Also known as: to_ary



99
# File 'lib/easysh.rb', line 99

def to_a;           each.to_a; end

#to_ioObject



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/easysh.rb', line 114

def to_io
  return unless cmd

  cur_opt    = opt.clone
  cur_chain  = (chain || []) + [[cmd, cur_opt]]
  pipes      = cur_chain.map { IO.pipe }
  n          = pipes.size
  cur_opt[0] = pipes[n-1][0] if n > 1
  lpid, lopt = nil
  pids       = []

  begin
    cur_chain.reverse.each_with_index do |cmd_opt, i|
      i      = n - 1 - i
      c, o   = *cmd_opt
      o      = o.clone
      o[1]   = nil           if i < n - 1
      o[1] ||= pipes[i][1]
      o[0]   = pipes[i-1][0] if i > 0
      pid = spawn(*c, o)
      pids << pid
      lopt, lpid = o, pid    if i == n - 1
    end

    if lopt[1] == pipes[n-1][1]
      rfd = pipes[n-1][0]
      (pipes.flatten-[rfd]).each { |io| io.close unless io.closed?  }
      yield rfd
    end
  ensure
    pipes.flatten.each { |io| io.close unless io.closed? }
    @exitstatus = Process.wait2(lpid)[-1] rescue nil
    ['TERM', 'KILL'].each { |sig| Process.kill sig, *pids rescue nil }
    Process.waitall rescue nil
  end
end

#to_s(n = "\n") ⇒ Object Also known as: read, !



100
# File 'lib/easysh.rb', line 100

def to_s(n = "\n"); cmd ? to_a.join(n) : ''; end

#|(sh, &block) ⇒ Object

Raises:

  • (TypeError)


106
107
108
109
# File 'lib/easysh.rb', line 106

def |(sh, &block)
  raise TypeError.new("EasySH expected, got #{sh.inspect}") unless sh.is_a? EasySH
  self.class.new sh.cmd, sh.opt, [*chain, cmd && [cmd, opt || {}], *sh.chain].compact, instant
end