readme: update

This commit is contained in:
ge
2026-01-03 19:18:15 +03:00
parent 055dab663e
commit 3cd5e40ac8

View File

@@ -1,25 +1,23 @@
# Run External Commands
`runcmd` module implements high-level interface for running external commands.
`runcmd` module implements a high-level interface for running external commands.
## Why not vlib `os`?
The standard V `os` module already contains tools for a similar tasks — `os.Process`,
`os.Command`, but I don't like any of them. There is also many functions for executing
external commands:
The standard V `os` module already contains many tools for running external commands,
but I don't like any of them. So let's overview.
* `os.execvp()`, `os.execve()` — cross-platform versions of the C functions of the same name.
* `os.execute()`, `os.execute_opt()`, `os.execute_or_exit()`, `os.execute_or_panic()`wrap C calls and wait for a command to completed. Under the hood, they perform a dirty hack by calling `sh` with stream redirection `'exec 2>&1;${cmd}'`. Only stdout and exit_code are available in result.
* `os.execute()`, `os.execute_opt()`, `os.execute_or_exit()`, `os.execute_or_panic()`starts and waits for a command to completed. Under the hood, they perform a dirty hack by calling shell with stream redirection `'exec 2>&1;${cmd}'`. Only stdout and exit_code are available in Result.
* `util.execute_with_timeout()` (from `os.util`) — just an `os.execute()` wrapper.
* `os.system()` — also executes command in the shell, but does not redirect streams. This is fine for running commands that take a long time and write something to the terminal; it's convenient in build scripts.
* `os.Process` just has an ugly interface with a lot of unnecessary methods. Actually, it's not bad; I copied parts of it.
* `os.Command` runs `popen()` under the hood and is not suitable for anything other than running a command in the shell (again) with stream processing of the mixed stdout and stderr.
This `runcmd` module is inspired by os/exec from the Go standard library and provides
a fairly flexible interface for starting child processes.
* `os.Command` calls `C.popen()` under the hood and is not suitable for anything other than running a command in the shell (again) with stream processing of the mixed stdout and stderr.
The obvious downside of this module is that it only works on Linux and likely other
POSIX-compliant operating systems. I'm not interested in working on MS Windows, but
@@ -38,20 +36,6 @@ cmd.run()! // Start and wait for process.
println(cmd.state) // exit status 0
```
You can create a `Command` object directly if that's more convenient. The following
example is equivalent to the first:
```v
import runcmd
mut cmd := runcmd.Command{
path: 'sh' // automatically resolves to actual path, e.g. /usr/bin/sh
args: ['-c', 'echo Hello, World!']
}
cmd.run()!
println(cmd.state)
```
If you don't want to wait for the child process to complete, call `start()` instead of `run()`:
```v
@@ -64,12 +48,13 @@ println(pid)
If you need to capture standard output and standard error, use the `output()` and
`combined_output()`. See examples in its description.
See also [examples](examples) dir for more examples.
To learn more about the `runcmd`'s capabilities and usage, see the [examples](examples)
directory. **Examples are very important**.
## Roadmap
- [x] Basic implementation.
- [ ] Contexts support for creating cancelable commands, commands with timeouts, etc.
- [x] Contexts support for creating cancelable commands, commands with timeouts, etc.
- [ ] Process groups support, pgkill().
- [ ] Better error handling and more tests...