-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
write_and_read_from_a_bash_child_process.v
97 lines (79 loc) · 2.8 KB
/
write_and_read_from_a_bash_child_process.v
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
88
89
90
91
92
93
94
95
96
97
module main
// This example shows how to communicate with a child process (`bash` in this case), by sending
// commands to its stdin pipe, and reading responses from its stdout and stderr pipes.
// Note, you can use `if p.is_pending(.stdout) {` and `if p.is_pending(.stderr) {`, to check if
// there is available data in the pipes, without having to block in your main loop, if the data
// is missing or just not available yet.
import os
import time
const tmp_folder = os.join_path(os.temp_dir(), 'process_folder')
const max_txt_files = 20
fn exec(cmd string) (string, int, string) {
mut out := []string{}
mut er := []string{}
mut rc := 0
mut p := os.new_process('/bin/bash')
p.set_redirect_stdio()
p.run()
p.stdin_write('echo "START " && sleep 0.1 && ${cmd};\n')
p.stdin_write('ECODE=\$?;\n')
p.stdin_write('sleep 0.1;\n')
p.stdin_write('exit \$ECODE;\n')
// Note, that you can also ensure that `bash` will exit, when the command finishes,
// by closing its stdin pipe. In the above example, that is not needed however, since
// the last `exit` command, will make it quit as well.
// os.fd_close(p.stdio_fd[0])
for p.is_alive() {
if data := p.pipe_read(.stderr) {
eprintln('p.pipe_read .stderr, len: ${data.len:4} | data: `${data#[0..10]}`...')
er << data
}
if data := p.pipe_read(.stdout) {
eprintln('p.pipe_read .stdout, len: ${data.len:4} | data: `${data#[0..10]}`...')
out << data
}
// avoid a busy loop, by sleeping a bit between each iteration
time.sleep(2 * time.millisecond)
}
// the process finished, slurp all the remaining data in the pipes:
out << p.stdout_slurp()
er << p.stderr_slurp()
p.close()
p.wait()
if p.code > 0 {
eprintln('----------------------------------------------------------')
eprintln('COMMAND: ${cmd}')
eprintln('STDOUT:\n${out}')
eprintln('STDERR:\n${er}')
eprintln('----------------------------------------------------------')
rc = 1
}
return out.join(''), rc, er.join('')
}
fn main() {
mut out := ''
mut er := ''
mut ecode := 0
// prepare some files in a temporary folder
defer {
os.rmdir_all(tmp_folder) or {}
}
os.mkdir_all(tmp_folder) or {}
for i in 0 .. max_txt_files {
os.write_file(os.join_path(tmp_folder, '${i}.txt'), '${i}\n${i}\n')!
}
out, ecode, er = exec("find ${os.quoted_path(tmp_folder)} ; sleep 0.1; find ${os.quoted_path(tmp_folder)} ; echo '******'")
assert out.ends_with('******\n')
assert er == ''
out, ecode, er = exec('echo to stdout')
assert out.contains('to stdout')
assert er == ''
out, ecode, er = exec('echo to stderr 1>&2')
assert out.starts_with('START')
assert er.contains('to stderr')
out, ecode, er = exec('ls /sssss')
assert out.starts_with('START')
assert er != ''
assert ecode > 0 // THIS STILL GIVES AN ERROR !
println('test ok stderr & stdout is indeed redirected, ecode: ${ecode}')
}