-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathshirt
executable file
·88 lines (68 loc) · 1.74 KB
/
shirt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/usr/bin/env ruby
require 'shellwords'
def main
loop do
$stdout.print ENV['PROMPT']
line = $stdin.gets
if line
line.strip!
else
exit
end
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)
placeholder_out.close
end
unless placeholder_in == $stdin
$stdin.reopen(placeholder_in)
placeholder_in.close
end
exec program, *arguments
}
end
def builtin?(program)
BUILTINS.has_key?(program)
end
def call_builtin(program, *arguments)
BUILTINS[program].call(*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