Bash: Tokenize string using shell rules without eval'ing it?

356 Views Asked by At

I'm writing a wrapper script. The original program's arguments are in a separate file, args. The script needs to split contents of args using shell parameter rules and then run the program. A partial solution (set + eval) was offered in Splitting a string to tokens according to shell parameter rules without eval:

#!/usr/bin/env bash
STDOUT="$1"
STDERR="$2"
( set -f ; eval "set -- $(cat args)"; exec run_in_container "$@" >"$STDOUT" 2>"$STDERR" )

but in my case args is user-generated. One can easily imagine

  • args: echo "Hello, 'world'! $(rm -rf /)" (not cool, but harmless: commands are run in a e.g. docker container)
  • args: bash -c "$JAVA_HOME/<...> > <...> && <...>" (harmful: $JAVA_HOME was intended to be container's value of environment variable JAVA_HOME, but actually will be substituted earlier, when eval'ing the command in the wrapper script's subshell.)

I tried Python, and this works:

#!/usr/bin/env python
import shlex, subprocess, sys

with open('args', 'r') as argsfile:
    args = argsfile.read()

with open(sys.argv[1], 'w') as outfile, open(sys.argv[2], 'w') as errfile:
    exit(subprocess.call(["run_in_container"] + shlex.split(args), stdout=outfile, stderr=errfile))

Is there a way to do shlex in bash: tokenize the string using shell parameter rules, but don't substitute any variables' values, don't execute $(...) etc.?

0

There are 0 best solutions below