123456789_123456789_123456789_123456789_123456789_

Class: Shell

Relationships & Source Files
Namespace Children
Modules:
Classes:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Forwardable, Exception2MessageMapper
Instance Chain:
self, Error
Inherits: Object
Defined in: lib/shell.rb,
lib/shell/builtin-command.rb,
lib/shell/command-processor.rb,
lib/shell/error.rb,
lib/shell/filter.rb,
lib/shell/process-controller.rb,
lib/shell/system-command.rb,
lib/shell/version.rb

Overview

Shell implements an idiomatic Ruby interface for common UNIX shell commands.

It provides users the ability to execute commands with filters and pipes, like sh/csh by using native facilities of Ruby.

Examples

Temp file creation

In this example we will create three tmpFile's in three different folders under the /tmp directory.

sh = Shell.cd("/tmp") # Change to the /tmp directory
sh.mkdir "shell-test-1" unless sh.exists?("shell-test-1")
# make the 'shell-test-1' directory if it doesn't already exist
sh.cd("shell-test-1") # Change to the /tmp/shell-test-1 directory
for dir in ["dir1", "dir3", "dir5"]
  if !sh.exists?(dir)
    sh.mkdir dir # make dir if it doesn't already exist
    sh.cd(dir) do
      # change to the `dir` directory
    f = sh.open("tmpFile", "w") # open a new file in write mode
    f.print "TEST\n"            # write to the file
    f.close                     # close the file handler
    end
    print sh.pwd                  # output the process working directory
  end
end

Temp file creation with self

This example is identical to the first, except we're using CommandProcessor#transact.

CommandProcessor#transact executes the given block against self, in this case sh; our Shell object. Within the block we can substitute sh.cd to .cd, because the scope within the block uses sh already.

sh = Shell.cd("/tmp")
sh.transact do
  mkdir "shell-test-1" unless exists?("shell-test-1")
  cd("shell-test-1")
  for dir in ["dir1", "dir3", "dir5"]
    if !exists?(dir)
    mkdir dir
    cd(dir) do
      f = open("tmpFile", "w")
      f.print "TEST\n"
      f.close
    end
    print pwd
    end
  end
end

Pipe /etc/printcap into a file

In this example we will read the operating system file /etc/printcap, generated by cupsd, and then output it to a new file relative to the #pwd of sh.

sh = Shell.new
sh.cat("/etc/printcap") | sh.tee("tee1") > "tee2"
(sh.cat < "/etc/printcap") | sh.tee("tee11") > "tee12"
sh.cat("/etc/printcap") | sh.tee("tee1") >> "tee2"
(sh.cat < "/etc/printcap") | sh.tee("tee11") >> "tee12"

Class Attribute Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(pwd, umask) ⇒ Object

Creates a Shell object which current directory is set to the process current directory, unless otherwise specified by the #pwd argument.

[ GitHub ]

  
# File 'lib/shell.rb', line 183

def initialize(pwd = Dir.pwd, umask = nil)
  @cwd = File.expand_path(pwd)
  @dir_stack = []
  @umask = umask

  @system_path = Shell.default_system_path
  @record_separator = Shell.default_record_separator

  @command_processor = CommandProcessor.new(self)
  @process_controller = ProcessController.new(self)

  @verbose = Shell.verbose
  @debug = Shell.debug
end

Class Attribute Details

.cascade (rw)

[ GitHub ]

  
# File 'lib/shell.rb', line 108

attr_accessor :cascade, :debug, :verbose

.default_record_separator (rw)

[ GitHub ]

  
# File 'lib/shell.rb', line 158

def default_record_separator
  if @default_record_separator
    @default_record_separator
  else
    $/
  end
end

.default_record_separator=(rs) (rw)

[ GitHub ]

  
# File 'lib/shell.rb', line 166

def default_record_separator=(rs)
  @default_record_separator = rs
end

.default_system_path (rw)

Returns the directories in the current shell's PATH environment variable as an array of directory names. This sets the system_path for all instances of Shell.

Example: If in your current shell, you did:

$ echo $PATH
/usr/bin:/bin:/usr/local/bin

Running this method in the above shell would then return:

["/usr/bin", "/bin", "/usr/local/bin"]
[ GitHub ]

  
# File 'lib/shell.rb', line 142

def default_system_path
  if @default_system_path
    @default_system_path
  else
    ENV["PATH"].split(":")
  end
end

.default_system_path=(path) (rw)

Sets the system_path that new instances of Shell should have as their initial system_path.

path should be an array of directory name strings.

[ GitHub ]

  
# File 'lib/shell.rb', line 154

def default_system_path=(path)
  @default_system_path = path
end

.verbose? (rw)

Alias for .verbose.

[ GitHub ]

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

alias verbose? verbose

Class Method Details

.alias_command(alias, command, *opts, &block)

Convenience method for CommandProcessor.alias_command. Defines an instance method which will execute a command under an alternative name.

Shell.def_system_command('date')
Shell.alias_command('date_in_utc', 'date', '-u')
Shell.new.date_in_utc # => Sat Jan 25 16:59:57 UTC 2014
[ GitHub ]

  
# File 'lib/shell.rb', line 392

def Shell.alias_command(ali, command, *opts, &block)
  CommandProcessor.alias_command(ali, command, *opts, &block)
end

.cd(path)

Creates a new Shell instance with the current working directory set to path.

[ GitHub ]

  
# File 'lib/shell.rb', line 125

def cd(path)
  new(path)
end

.debug Also known as: .debug?

[ GitHub ]

  
# File 'lib/shell.rb', line 108

attr_accessor :cascade, :debug, :verbose

.debug=(val)

[ GitHub ]

  
# File 'lib/shell.rb', line 114

attr_accessor :cascade, :debug, :verbose

.debug?

Alias for .debug.

[ GitHub ]

  
# File 'lib/shell.rb', line 110

alias debug? debug

.def_system_command(command, path = command)

Convenience method for CommandProcessor.def_system_command. Defines an instance method which will execute the given shell command. If the executable is not in .default_system_path, you must supply the path to it.

Shell.def_system_command('hostname')
Shell.new.hostname # => localhost

# How to use an executable that's not in the default path

Shell.def_system_command('run_my_program', "~/hello")
Shell.new.run_my_program # prints "Hello from a C program!"
[ GitHub ]

  
# File 'lib/shell.rb', line 372

def Shell.def_system_command(command, path = command)
  CommandProcessor.def_system_command(command, path)
end

.install_system_commands(pre = "sys_")

Convenience method for CommandProcessor.install_system_commands. Defines instance methods representing all the executable files found in .default_system_path, with the given prefix prepended to their names.

Shell.install_system_commands
Shell.new.sys_echo("hello") # => hello
[ GitHub ]

  
# File 'lib/shell.rb', line 412

def Shell.install_system_commands(pre = "sys_")
  CommandProcessor.install_system_commands(pre)
end

.notify(*opts)

[ GitHub ]

  
# File 'lib/shell.rb', line 425

def self.notify(*opts)
  Shell::debug_output_synchronize do
    if opts[-1].kind_of?(String)
      yorn = verbose?
    else
      yorn = opts.pop
    end
    return unless yorn

    if @debug_display_thread_id
      if @debug_display_process_id
        prefix = "shell(##{Process.pid}:#{Thread.current.to_s.sub("Thread", "Th")}): "
      else
        prefix = "shell(#{Thread.current.to_s.sub("Thread", "Th")}): "
      end
    else
      prefix = "shell: "
    end
    _head = true
    STDERR.print opts.collect{|mes|
      mes = mes.dup
      yield mes if iterator?
      if _head
        _head = false
        prefix + mes
      else
        " "* prefix.size + mes
      end
    }.join("\n")+"\n"
  end
end

.unalias_command(ali)

Convenience method for CommandProcessor.unalias_command

[ GitHub ]

  
# File 'lib/shell.rb', line 397

def Shell.unalias_command(ali)
  CommandProcessor.unalias_command(ali)
end

.undef_system_command(command)

Convenience method for CommandProcessor.undef_system_command

[ GitHub ]

  
# File 'lib/shell.rb', line 377

def Shell.undef_system_command(command)
  CommandProcessor.undef_system_command(command)
end

.verbose (rw) Also known as: .verbose?

[ GitHub ]

  
# File 'lib/shell.rb', line 108

attr_accessor :cascade, :debug, :verbose

Instance Attribute Details

#command_processor (readonly)

[ GitHub ]

  
# File 'lib/shell.rb', line 223

attr_reader :command_processor

#cwd (readonly) Also known as: #dir, #getwd, #pwd

Returns the current working directory.

[ GitHub ]

  
# File 'lib/shell.rb', line 243

attr_reader :cwd

#debug? (readonly)

Alias for #debug.

[ GitHub ]

  
# File 'lib/shell.rb', line 221

alias debug? debug

#dir (readonly)

Alias for #cwd.

[ GitHub ]

  
# File 'lib/shell.rb', line 244

alias dir cwd

#dir_stack (readonly) Also known as: #dirs

[ GitHub ]

  
# File 'lib/shell.rb', line 248

attr_reader :dir_stack

#dirs (readonly)

Alias for #dir_stack.

[ GitHub ]

  
# File 'lib/shell.rb', line 249

alias dirs dir_stack

#getwd (readonly)

Alias for #cwd.

[ GitHub ]

  
# File 'lib/shell.rb', line 245

alias getwd cwd

#process_controller (readonly)

[ GitHub ]

  
# File 'lib/shell.rb', line 224

attr_reader :process_controller

#pwd (readonly)

Alias for #cwd.

[ GitHub ]

  
# File 'lib/shell.rb', line 246

alias pwd cwd

#record_separator (rw)

[ GitHub ]

  
# File 'lib/shell.rb', line 212

attr_accessor :record_separator

#system_path (rw)

Returns the command search path in an array

[ GitHub ]

  
# File 'lib/shell.rb', line 199

attr_reader :system_path

#system_path=(path) (rw)

Sets the system path (the Shell instance's PATH environment variable).

path should be an array of directory name strings.

[ GitHub ]

  
# File 'lib/shell.rb', line 204

def system_path=(path)
  @system_path = path
  rehash
end

#umask (rw)

Returns the umask

[ GitHub ]

  
# File 'lib/shell.rb', line 211

attr_accessor :umask

#verbose? (rw)

Alias for #verbose.

[ GitHub ]

  
# File 'lib/shell.rb', line 220

alias verbose? verbose

Instance Method Details

#cd(path = nil, verbose = @verbose)

Alias for #chdir.

[ GitHub ]

  
# File 'lib/shell.rb', line 281

alias cd chdir

#chdir(path) Also known as: #cd

Creates a Shell object which current directory is set to path.

If a block is given, it restores the current directory when the block ends.

If called as iterator, it restores the current directory when the block ends.

[ GitHub ]

  
# File 'lib/shell.rb', line 260

def chdir(path = nil, verbose = @verbose)
  check_point

  if iterator?
    notify("chdir(with block) #{path}") if verbose
    cwd_old = @cwd
    begin
      chdir(path, nil)
      yield
    ensure
      chdir(cwd_old, nil)
    end
  else
    notify("chdir #{path}") if verbose
    path = "~" unless path
    @cwd = expand_path(path)
    notify "current dir: #{@cwd}"
    rehash
    Void.new(self)
  end
end

#debug (readonly) Also known as: #debug?

[ GitHub ]

  
# File 'lib/shell.rb', line 213

attr_accessor :verbose, :debug

#debug=(val) (readonly)

[ GitHub ]

  
# File 'lib/shell.rb', line 215

attr_accessor :verbose, :debug

#expand_path(path)

[ GitHub ]

  
# File 'lib/shell.rb', line 226

def expand_path(path)
  File.expand_path(path, @cwd)
end

#inspect

[ GitHub ]

  
# File 'lib/shell.rb', line 417

def inspect
  if debug.kind_of?(Integer) && debug > 2
    super
  else
    to_s
  end
end

#jobs

Returns a list of scheduled jobs.

[ GitHub ]

  
# File 'lib/shell.rb', line 344

def jobs
  @process_controller.jobs
end

#kill(signal, job)

Sends the given signal to the given job

[ GitHub ]

  
# File 'lib/shell.rb', line 352

def kill(sig, command)
  @process_controller.kill_job(sig, command)
end

#popd

Alias for #popdir.

[ GitHub ]

  
# File 'lib/shell.rb', line 341

alias popd popdir

#popdir Also known as: #popd

Pops a directory from the directory stack, and sets the current directory to it.

[ GitHub ]

  
# File 'lib/shell.rb', line 328

def popdir
  check_point

  notify("popdir")
  if pop = @dir_stack.pop
    chdir pop
    notify "dir stack: [#{@dir_stack.join ', '}]"
    self
  else
    Shell.Fail DirStackEmpty
  end
  Void.new(self)
end

#pushd(path = nil, verbose = @verbose)

Alias for #pushdir.

[ GitHub ]

  
# File 'lib/shell.rb', line 324

alias pushd pushdir

#pushdir(path) #pushdir(path)
Also known as: #pushd

Pushes the current directory to the directory stack, changing the current directory to path.

If path is omitted, it exchanges its current directory and the top of its directory stack.

If a block is given, it restores the current directory when the block ends.

[ GitHub ]

  
# File 'lib/shell.rb', line 294

def pushdir(path = nil, verbose = @verbose)
  check_point

  if iterator?
    notify("pushdir(with block) #{path}") if verbose
    pushdir(path, nil)
    begin
      yield
    ensure
      popdir
    end
  elsif path
    notify("pushdir #{path}") if verbose
    @dir_stack.push @cwd
    chdir(path, nil)
    notify "dir stack: [#{@dir_stack.join ', '}]"
    self
  else
    notify("pushdir") if verbose
    if pop = @dir_stack.pop
      @dir_stack.push @cwd
      chdir pop
      notify "dir stack: [#{@dir_stack.join ', '}]"
      self
    else
      Shell.Fail DirStackEmpty
    end
  end
  Void.new(self)
end

#verbose (rw) Also known as: #verbose?

[ GitHub ]

  
# File 'lib/shell.rb', line 213

attr_accessor :verbose, :debug