Skip to content

Instantly share code, notes, and snippets.

@usmanbashir
Created January 19, 2015 15:01
Show Gist options
  • Save usmanbashir/5e25852b10f43b61e7a1 to your computer and use it in GitHub Desktop.
Save usmanbashir/5e25852b10f43b61e7a1 to your computer and use it in GitHub Desktop.
A Unix Shell In Ruby
#!/usr/bin/env ruby
require 'shellwords'
def main
loop do
$stdout.print ENV['PROMPT']
line = $stdin.gets
if line
line.strip!
else
# in the case, EOF was received on $stdin
exit
end
command, *arguments = Shellwords.shellsplit(line)
if BUILTINS[command]
BUILTINS[command].call(*arguments)
else
pid = fork {
exec command, *arguments
}
Process.wait pid
end
end
end
def main2
loop do
$stdout.print ENV['PROMPT']
line = $stdin.gets
commands = split_on_pipes(line)
placeholder_in = $stdin
placeholder_out = $stdout
pipe = []
commands.each_with_index do |command, index|
program, *arguments = Shellwords.shellsplit(command)
if builtin?(program)
call_builtin(program, *arguments)
else
if index+1 < commands.size
pipe = IO.pipe
placeholder_out = pipe.last
else
placeholder_out = $stdout
end
spawn_program(program, *arguments, placeholder_out, placeholder_in)
placeholder_out.close unless placeholder_out == $stdout
placeholder_in.close unless placeholder_in == $stdin
placeholder_in = pipe.first
end
end
Process.waitall
end
end
def split_on_pipes(line)
line.scan( /([^"'|]+)|["']([^"']*)["']/ ).flatten.compact
end
def spawn_program(program, *arguments, placeholder_out, placeholder_in)
fork {
unless placeholder_out == $stdout
$stdout.reopen(placeholder_out)
placeholdder_out.close
end
unless placeholder_in == $stdin
$stdin.reopen(placeholder_in)
placeholder_in.close
end
exec program, *arguments
}
end
BUILTINS = {
'cd' => lambda { |dir = ENV['HOME']| Dir.chdir(dir) },
'exit' => lambda { |code = 0| exit(code.to_i) },
'exec' => lambda { |*command| exec *command },
'set' => lambda { |args|
key, value = args.split('=')
ENV[key] = value
}
}
ENV['PROMPT'] = '> '
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment