v / examples / process / write_and_read_from_a_bash_child_process.v
98 lines · 80 sloc · 2.8 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
Raw
1module main
2
3// This example shows how to communicate with a child process (`bash` in this case), by sending
4// commands to its stdin pipe, and reading responses from its stdout and stderr pipes.
5// Note, you can use `if p.is_pending(.stdout) {` and `if p.is_pending(.stderr) {`, to check if
6// there is available data in the pipes, without having to block in your main loop, if the data
7// is missing or just not available yet.
8import os
9import time
10
11const tmp_folder = os.join_path(os.temp_dir(), 'process_folder')
12
13const max_txt_files = 20
14
15fn exec(cmd string) (string, int, string) {
16 mut out := []string{}
17 mut er := []string{}
18 mut rc := 0
19
20 mut p := os.new_process('/bin/bash')
21 p.set_redirect_stdio()
22 p.run()
23
24 p.stdin_write('echo "START " && sleep 0.1 && ${cmd};\n')
25 p.stdin_write('ECODE=\$?;\n')
26 p.stdin_write('sleep 0.1;\n')
27 p.stdin_write('exit \$ECODE;\n')
28
29 // Note, that you can also ensure that `bash` will exit, when the command finishes,
30 // by closing its stdin pipe. In the above example, that is not needed however, since
31 // the last `exit` command, will make it quit as well.
32 // os.fd_close(p.stdio_fd[0])
33
34 for p.is_alive() {
35 if data := p.pipe_read(.stderr) {
36 eprintln('p.pipe_read .stderr, len: ${data.len:4} | data: `${data#[0..10]}`...')
37 er << data
38 }
39 if data := p.pipe_read(.stdout) {
40 eprintln('p.pipe_read .stdout, len: ${data.len:4} | data: `${data#[0..10]}`...')
41 out << data
42 }
43 // avoid a busy loop, by sleeping a bit between each iteration
44 time.sleep(2 * time.millisecond)
45 }
46
47 // the process finished, slurp all the remaining data in the pipes:
48 out << p.stdout_slurp()
49 er << p.stderr_slurp()
50 p.close()
51 p.wait()
52
53 if p.code > 0 {
54 eprintln('----------------------------------------------------------')
55 eprintln('COMMAND: ${cmd}')
56 eprintln('STDOUT:\n${out}')
57 eprintln('STDERR:\n${er}')
58 eprintln('----------------------------------------------------------')
59 rc = 1
60 }
61
62 return out.join(''), rc, er.join('')
63}
64
65fn main() {
66 mut out := ''
67 mut er := ''
68 mut ecode := 0
69
70 // prepare some files in a temporary folder
71 defer {
72 os.rmdir_all(tmp_folder) or {}
73 }
74 os.mkdir_all(tmp_folder) or {}
75 for i in 0 .. max_txt_files {
76 os.write_file(os.join_path(tmp_folder, '${i}.txt'), '${i}\n${i}\n')!
77 }
78
79 out, ecode, er =
80 exec("find ${os.quoted_path(tmp_folder)} ; sleep 0.1; find ${os.quoted_path(tmp_folder)} ; echo '******'")
81 assert out.ends_with('******\n')
82 assert er == ''
83
84 out, ecode, er = exec('echo to stdout')
85 assert out.contains('to stdout')
86 assert er == ''
87
88 out, ecode, er = exec('echo to stderr 1>&2')
89 assert out.starts_with('START')
90 assert er.contains('to stderr')
91
92 out, ecode, er = exec('ls /sssss')
93 assert out.starts_with('START')
94 assert er != ''
95 assert ecode > 0 // THIS STILL GIVES AN ERROR !
96
97 println('test ok stderr & stdout is indeed redirected, ecode: ${ecode}')
98}
99