diff --git a/Sources/ContainerCommands/Machine/MachineRun.swift b/Sources/ContainerCommands/Machine/MachineRun.swift index dc62132ca..5cc704c46 100644 --- a/Sources/ContainerCommands/Machine/MachineRun.swift +++ b/Sources/ContainerCommands/Machine/MachineRun.swift @@ -29,7 +29,12 @@ extension Application { public static let configuration = CommandConfiguration( commandName: "run", - abstract: "Run a command or interactive shell in a container machine, booting the container machine if necessary" + abstract: "Run a command or interactive shell in a container machine, booting the container machine if necessary", + discussion: """ + When is provided, the command and arguments are joined into a + single string and evaluated by the guest user's shell (shell -c "$*"), + including expansion, substitution, and redirection. This is not argv-preserving. + """ ) @OptionGroup @@ -47,10 +52,10 @@ extension Application { @Flag(name: .long, help: "Run as root instead of matching host user") var root: Bool = false - @Argument(help: "Command to run (default: login shell)") + @Argument(help: "Command evaluated by the guest shell (default: login shell)") var executable: String? - @Argument(parsing: .captureForPassthrough, help: "Command arguments") + @Argument(parsing: .captureForPassthrough, help: "Words joined with the command and evaluated via shell -c") var arguments: [String] = [] public func run() async throws { diff --git a/docs/command-reference.md b/docs/command-reference.md index c7d854806..25970bd18 100644 --- a/docs/command-reference.md +++ b/docs/command-reference.md @@ -1125,6 +1125,8 @@ container machine create --virtualization --kernel ./vmlinux-kvm alpine:3.22 Runs a command in a container machine, booting it first if needed. With no command, it opens an interactive login shell. By default the command runs as a user matching the host user. +When a command is provided, `` and `` are joined into a single string and evaluated by the execution user's shell inside the guest (`shell -c "$*"`). Expansion, substitution, and redirection apply. This differs from argv-preserving interfaces such as `docker exec`. + **Usage** ```bash @@ -1133,8 +1135,8 @@ container machine run [] [] [ ...] **Arguments** -* ``: Command to run (default: login shell) -* ``: Command arguments +* ``: Command evaluated by the guest shell (default: login shell) +* ``: Additional words joined into the shell command string **Options** @@ -1164,6 +1166,9 @@ container machine run -n my-machine uname -a # pass arguments to the command after -- container machine run -n my-machine -- cat /proc/cpuinfo + +# shell evaluation: quote a script string when you need spaces or substitution +container machine run -n my-machine -- 'printf ":%s:" "one two three"' ``` ### `container machine list (ls)` diff --git a/docs/container-machine.md b/docs/container-machine.md index 81e36e562..21e57794e 100644 --- a/docs/container-machine.md +++ b/docs/container-machine.md @@ -40,6 +40,19 @@ container machine run -n dev uname -a container machine run -n dev -- cat /proc/cpuinfo ``` +Commands are **not** argv-preserving. The guest joins `` and `` into one string and evaluates it with the execution user's shell: + +```sh +exec "${USER_SHELL:-${SHELL}}" -c "$*" +``` + +That shell performs expansion, substitution, and redirection. For example, `printf ':%s:' 'one two three'` becomes three words after joining, and `$(...)` inside an argument is evaluated in the guest. Quote a single shell script string when you need spaces or metacharacters preserved as one argument to the guest shell: + +```bash +container machine run -n dev -- 'printf ":%s:" "one two three"' +container machine run -n dev -- 'echo "uid=$(id -u)"' +``` + ### Set a default Pick a default container machine so you can drop the `-n` flag: