Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 140 lines (96 sloc) 4.216 kb
585145f @gdb Initial commit
authored
1 # Rubysh
2
586648e @gdb Update description
authored
3 Rubysh: Ruby subprocesses made easy
585145f @gdb Initial commit
authored
4
980eac8 @gdb Update docs
authored
5 Rubysh makes shelling out easy with a __sh__-like syntax layer for Ruby:
585145f @gdb Initial commit
authored
6
980eac8 @gdb Update docs
authored
7 irb -r rubysh
8 >> command = Rubysh('echo', 'hello-from-Rubysh') | Rubysh('grep', '--color', 'Rubysh')
9 >> command.run
10 hello-from-Rubysh
11 => Rubysh::Runner: echo hello-from-Rubysh | grep --color Rubysh (exitstatus: 0)
585145f @gdb Initial commit
authored
12
980eac8 @gdb Update docs
authored
13 Rubysh philosophy is to make simple tasks simple and complex tasks
14 possible.
585145f @gdb Initial commit
authored
15
980eac8 @gdb Update docs
authored
16 ## Motivation
585145f @gdb Initial commit
authored
17
980eac8 @gdb Update docs
authored
18 Existing Ruby shell libaries make it very difficult to do tasks that
19 are simple in __sh__, such as:
585145f @gdb Initial commit
authored
20
980eac8 @gdb Update docs
authored
21 - piping the output from one program to another
22 - redirecting a program's output to a file
23 - use a pre-tokenized array of arguments
585145f @gdb Initial commit
authored
24
565a14d @gdb Update README
authored
25 (Some existing libraries make some of these tasks easy, but not all of
26 them at once.) Rubysh tries to emulate __sh__'s interface and
27 semantics as closely as possible.
980eac8 @gdb Update docs
authored
28
29 ## Features
30
31 Redirecting a file descriptor to a file:
32
33 # echo hello-from-Rubysh >/tmp/file.txt
34 Rubysh('echo', 'hello-from-Rubysh', Rubysh.stdout > '/tmp/file.txt')
35 Rubysh('echo', 'hello-from-Rubysh', Rubysh::FD(1) > '/tmp/file.txt')
36
37 Redirecting a file descriptor to another file descriptor:
38
39 # echo hello-from-Rubysh 2>&1
40 Rubysh('echo', 'hello-from-Rubysh', Rubysh.stderr > Rubysh.stdout)
41
42 Feeding standard input with a string literal:
43
44 # cat <<< "hello there"
45 Rubysh('cat', Rubysh.<<< 'hello there')
46
47 Rubysh has been written to work with arbitrary file descriptors, so
48 you can do the same advanced FD redirection magic you can in __sh__:
49
50 # cat 3<<< "hello there" <&3
51 Rubysh('cat', Rubysh::FD(3).<<< 'hello there', Rubysh.stdin < Rubysh::FD(3))
585145f @gdb Initial commit
authored
52
980eac8 @gdb Update docs
authored
53 You can also capture output to a named target (here :stdout, :stderr
54 are arbitrary symbols):
585145f @gdb Initial commit
authored
55
980eac8 @gdb Update docs
authored
56 command = Rubysh('echo', 'hi', Rubysh.stdout > :stdout, Rubysh.stderr > :stderr)
57 runner = command.run
855cbba @gdb Fix lurking .datas
authored
58 runner.read(:stdout) # "hi\n"
59 runner.read(:stderr) # ""
980eac8 @gdb Update docs
authored
60
78b6eeb @gdb Allow running Rubysh with a block
authored
61 You can also have your child run a Ruby block rather than execute a command:
62
63 command = Rubysh(Rubysh.stdout > :stdout) {puts "hi from child"}
64 runner = command.run
65 runner.read(:stdout) # "hi from child\n"
66
a4b7a9a @gdb Add example of input/output
authored
67 ## Controlled input
68
69 You can easily read and write data interactively:
70
71 >> runner = Rubysh('examples/dots.sh', Rubysh.>).run_async
72 => Rubysh::Runner: examples/dots.sh >:stdout (readers: :stdout, pid: 78296)
73 >> runner.read(:how => :partial) # block until some output available
74 => ".\n.\n.\n.\n.\n.\n.\n.\n.\n"
75 >> runner.read(:how => :nonblock)
86456f2 @gdb Add on_read
authored
76 => nil
a4b7a9a @gdb Add example of input/output
authored
77 >> runner.read # block until all output available
86456f2 @gdb Add on_read
authored
78 => ".\n[...]"
79
80 ## Reactive output
81
82 You can also receive real-time notifications as data becomes available:
83
84 >> runner = Rubysh(
85 'examples/on_read_example.sh',
86 Rubysh.stdout > :stdout, Rubysh.stderr > :stderr,
87 on_read: Proc.new {|target, data| puts "[#{target}]: #{data}"}
88 )
89 => Command: examples/on_read_example.sh >:stdout 2>:stderr {:on_read=>#<Proc:0x007f8ad3bc5790@(irb):4>}
90 >> runner.run
91 [stdout]: [1] Hello from stdout
92 [stderr]: [1] Hello from stderr
93 [stdout]: [2] Hello from stdout
94 [stderr]: [2] Hello from stderr
95 [...]
980eac8 @gdb Update docs
authored
96
97 ## API
98
565a14d @gdb Update README
authored
99 The Rubysh helper function produces instances of `BaseCommand`. You
100 can run `run` on these to spawn a subprocess and then `wait` for
980eac8 @gdb Update docs
authored
101 it to complete. Alternatively, you can do:
102
103 command = Rubysh('ls')
104 runner = command.run_async
105 runner.wait
106
1edd3fb @gdb Add an AliasRubysh method
authored
107 If you don't want to type `Rubysh` all the time, you can alias it with
108 the `AliasRubysh` helper:
109
110 AliasRubysh(:R)
111 R('ls')
112
565a14d @gdb Update README
authored
113 ## Safety
114
115 Rubysh takes a splatted array argument as a command specification. In
116 particular, it doesn't convert it back and forth a command-line
117 string, meaning you don't have to worry about spaces in
3ecaf42 @gdb Update README
authored
118 arguments. (You should still always think twice before putting
565a14d @gdb Update README
authored
119 untrusted arguments into a shell argument.)
120
980eac8 @gdb Update docs
authored
121 ## Installation
122
123 Rubysh is hosted on Rubygems. You can install by adding this line to
124 your application's Gemfile:
125
126 gem 'rubysh'
127
128 Or by installing directly via
129
130 $ gem install rubysh
585145f @gdb Initial commit
authored
131
132 ## Contributing
133
980eac8 @gdb Update docs
authored
134 Patches welcome! I'm happy to merge pull requests.
565a14d @gdb Update README
authored
135
136 ## Future features
137
135407c @gdb Update future features
authored
138 - Better support for streaming output
565a14d @gdb Update README
authored
139 - Subshell syntax (`cat <(ls)`, `echo $(ls)`)
Something went wrong with that request. Please try again.