Avoid shell double-evaluation (part 2)
In an earlier
post I
demonstrated a simple shell script that can be used to invoke adb shell
and/or ssh without evaluating arguments a second time.
But what if you want to run something as root? It turns out it just works.
AOSP's su and Linux's sudo do what I consider the right thing: They
preserve arguments without evaluating them.
$ run-escaped 'adb shell su 0' /data/local/tmp/echo-args.sh 'hello world'
"hello world"
$ run-escaped 'ssh remotebox sudo' echo-args.sh 'hello world'
"hello world"
(Note: If your remotebox requires a password for sudo, you'll want to pass -t
to ssh to force pseudo-tty allocation - otherwise you'll get an error like
sudo: a terminal is required to read the password; either use the -S option to
read from standard input or configure an askpass helper)
It gets more complicated if you want to run as root and evaluate your
arguments. The naive thing will evaluate arguments as the shell user and then
pass them to root.
$ adb shell su 0 'echo $(whoami)'
shell
Therefore, I've written a new version of run-escaped that provides an option
for evaluating its arguments:
run-escaped() {
eval_args=""
while [ "$#" -gt 0 ]; do
case "$1" in
-e|--eval-args) eval_args=yes; shift ;;
--) shift; break ;;
-*) die "unknown option $1" ;;
*) break ;;
esac
done
# e.g. `adb shell`, `adb shell su 0`, `ssh remotebox`, `ssh remotebox sudo`
shell="$1"
shift
if [ -n "$eval_args" ]; then
maybeEval='eval "$*"'
else
maybeEval='"$@"'
fi
set -- sh -c "$maybeEval" -- "$@"
$shell "$(printf " %q" "$@")"
}
You can use it like this:
$ run-escaped --eval-args 'adb shell su 0' 'echo $(whoami)'
root
$ run-escaped --eval-args 'ssh remotebox sudo' 'echo $(whoami)'
root
It works by quoting its arguments, and explicitly invoking eval "$*" within
sh (running as root) (as opposed to letting adb shell / ssh do it
implicitly).
If you enjoyed this post, please let me know on Twitter or Bluesky.
Posted December 24, 2025.