OpenWrt pct_remote Shell Syntax Rules
Shell Execution Through pct_remote
- The
community.proxmox.proxmox_pct_remoteconnection plugin builds/usr/sbin/pct exec <vmid> -- <cmd>and sends it as a single string via SSH to the Proxmox host. The HOST's bash interprets the entire string beforepct execruns.
Critical Shell Syntax Issues
Semicolons split at host level.
cmd1; cmd2becomes two separate commands on the Proxmox host — onlycmd1runs inside the container.Pipes split at host level.
cmd1 | cmd2—cmd1runs inside the container,cmd2runs on the HOST (filtering stdout from the container). This happens to work for text processing but is fragile.exportis NOT a binary.lxc-attachtries to exec the first word of the command as a binary.exportis a shell builtin — it fails withlxc-attach: Failed to exec "export".PATH is not set inside the container.
lxc-attach'sexecvpuses the default path (/bin:/usr/bin), which misses/sbinand/usr/sbinwhere OpenWrt putsuci,wifi,iw.
Solution: sh -c Wrapper Pattern
- ALWAYS wrap all commands in
/bin/sh -c '...'. The single quotes protect the payload from host bash. Inside the container, busybox ash provides its defaultPATH=/sbin:/usr/sbin:/bin:/usr/bin.
# BAD — semicolons split at host level, export is not a binary
- ansible.builtin.raw: >-
export PATH="/usr/sbin:/usr/bin:/sbin:/bin:$PATH";
opkg update
# BAD — for loops break (host bash tries to exec "for")
- ansible.builtin.raw: >-
for mod in iwlwifi ath9k; do modprobe "$mod" 2>/dev/null; done
# GOOD — sh -c wraps everything in a container-side shell
- ansible.builtin.raw: >-
/bin/sh -c 'opkg update'
# GOOD — complex commands with semicolons inside sh -c
- ansible.builtin.raw: >-
/bin/sh -c
'opkg list-installed 2>/dev/null | grep -c wpad-mesh || true'
# GOOD — multi-command chains use && inside sh -c
- ansible.builtin.raw: >-
/bin/sh -c
'uci set wireless.mesh0=wifi-iface &&
uci set wireless.mesh0.device="radio0" &&
uci commit wireless'
Quoting Rules for sh -c Through pct_remote
Outer single quotes protect the entire payload from host bash.
Inside, use double quotes for values:
uci set foo.bar="value"NEVER nest single quotes — use double quotes or drop quotes for simple alphanumeric values.
&&and||inside single quotes are interpreted by container ash.[ ... ] && echo x || echo yWITHOUT sh -c is OK —[is exec'd by lxc-attach,&&/||chain at host level (works for simple checks).
pct exec PATH Limitation
pct exec(andlxc-attach) uses a restricted PATH:/sbin:/bin:/usr/sbin:/usr/bin. Binaries in/usr/local/bin/(e.g.,pihole) are NOT found.ALWAYS use full paths for binaries in
/usr/local/bin/or/opt/when running viapct exec,pct_remote, oransible.builtin.commandon containers.Previous bug:
pihole -a -pviapct_remotefailed with[Errno 2] No such file or directory: b'pihole'. The binary was at/usr/local/bin/piholebut PATH didn't include it.