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"
Returns the command search path in an array
Returns the umask
Returns the current working directory.
Returns the current working directory.
Returns the current working directory.
Returns the current working directory.
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 394
def Shell.alias_command(ali, command, *opts, &block)
CommandProcessor.alias_command(ali, command, *opts, &block)
end
Convenience method for Shell::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
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 126
def cd(path)
new(path)
end
Creates a new Shell
instance with the current working directory set to path
.
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 115
def debug=(val)
@debug = val
@verbose = val if val
end
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 374
def Shell.def_system_command(command, path = command)
CommandProcessor.def_system_command(command, path)
end
Convenience method for Shell::CommandProcessor.def_system_command
. Defines an instance method which will execute the given shell command. If the executable is not in Shell.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!"
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 159
def default_record_separator
if @default_record_separator
@default_record_separator
else
$/
end
end
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 167
def default_record_separator=(rs)
@default_record_separator = rs
end
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 143
def default_system_path
if @default_system_path
@default_system_path
else
ENV["PATH"].split(":")
end
end
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"]
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 155
def default_system_path=(path)
@default_system_path = path
end
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.
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 414
def Shell.install_system_commands(pre = "sys_")
CommandProcessor.install_system_commands(pre)
end
Convenience method for Shell::CommandProcessor.install_system_commands. Defines instance methods representing all the executable files found in Shell.default_system_path
, with the given prefix prepended to their names.
Shell.install_system_commands Shell.new.sys_echo("hello") # => hello
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 184
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
Creates a Shell
object which current directory is set to the process current directory, unless otherwise specified by the pwd
argument.
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 427
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
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 399
def Shell.unalias_command(ali)
CommandProcessor.unalias_command(ali)
end
Convenience method for Shell::CommandProcessor.unalias_command
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 379
def Shell.undef_system_command(command)
CommandProcessor.undef_system_command(command)
end
Convenience method for Shell::CommandProcessor.undef_system_command
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 262
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
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.
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 217
def debug=(val)
@debug = val
@verbose = val if val
end
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 228
def expand_path(path)
File.expand_path(path, @cwd)
end
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 419
def inspect
if debug.kind_of?(Integer) && debug > 2
super
else
to_s
end
end
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 346
def jobs
@process_controller.jobs
end
Returns a list of scheduled jobs.
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 354
def kill(sig, command)
@process_controller.kill_job(sig, command)
end
Sends the given signal
to the given job
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 330
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
Pops a directory from the directory stack, and sets the current directory to it.
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 296
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
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.
# File tmp/rubies/ruby-2.5.9/lib/shell.rb, line 205
def system_path=(path)
@system_path = path
rehash
end
Sets the system path (the Shell
instance’s PATH environment variable).
path
should be an array of directory name strings.