How to pass command line parameters with quotes stored in single variable?

前端 未结 5 1092
闹比i
闹比i 2021-01-07 03:58

I want to call external application from shell script, but this shell script gets parameters (from other script) in a single variable. All was OK until I did not have to use

5条回答
  •  孤街浪徒
    2021-01-07 04:19

    Avoid passing the whole thing as a single argument (as you do with the squotes). It's hard enough to make shell scripts that carefully preserve the number of arguments passed, without needing to make it harder by flattening them into strings and expanding them again.

    If you do need to though, there are some best practices to follow. I had to write a script a while back that serves as a su/sudo wrapper: su takes a single argument that it passes to sh to evaluate; sudo takes any number of arguments that it passes on unmodified to an execv(e).

    You have to be pretty careful about getting it portable and not running into problems in obscure shells. The whole script isn't very useful to post, but the general gist is to write some escaping functions and very perform the quoting to build up a bullet-proof, unreadably-cautiously escaped string that's safe to pass to eval.

    bash_escape() {
      # backtick indirection strictly necessary here: we use it to strip the
      # trailing newline from sed's output, which Solaris/BSD sed *always* output
      # (unlike GNU sed, which outputs "test": printf %s test | sed -e s/dummy//)
      out=`echo "$1" | sed -e s/\\'/\\''\\\\'\\'\\'/g`
      printf \'%s\' "$out"
    }
    append_bash_escape() {
      printf "%s " "$1"
      bash_escape "$2"
    }
    sed_escape() {
      out=`echo "$1" | sed -e 's/[\\/&]/\\\\&/g'`
      printf %s "$out"
    }
    

    These useful functions let you do something like this to portably build command strings:

    COMMAND=
    while [ $# -gt 0 ] ; do
      COMMAND=`append_bash_escape "$COMMAND" "$1"` ; shift
    done
    

    You can then manipulate the command string, for example by running bash_escape on it and using sed_escape to substitute into the string "su - root -c SUB_HERE", or just substitute it directly into a string like "sudo -- SUB_HERE". You then have something you can safely eval without worrying about metacharacters, argument splitting, unescaped globs, and so on.

    Be paranoid, and unittest your script with every nasty input you can think of to make sure your argument splitting and preserving really is correct!

提交回复
热议问题