Avoiding shell double-evaluation (part 2)

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.

Tags: #android, #shell