How to substitute quoted, multi-word strings as arguments?

前端 未结 4 1773
一整个雨季
一整个雨季 2020-12-01 21:08

I\'m trying to substitute a string variable, containing multiple quoted words, as a parameter to a command.

Thus, given the following example script (Note the -x in

相关标签:
4条回答
  • 2020-12-01 21:45

    There is a portable way to split expand a variable but keep spaces. Bash arrays are not needed. Dash (Ubuntu's /bin/sh) would work too.

    Use some character to separate arguments that is definitely not used inside the arguments. The below example uses semicolon, but it could be a newline or another character. Change the IFS variable to a newline temporarily when the list of arguments is expanded. Restore IFS to the original value as soon as possible, even if it means doing it in the loop. If the loop is not guaranteed to run at least once, do it after the loop as well.

    #! /bin/sh
    arg_list='hello world;have a nice day'
    save_IFS="$IFS"
    IFS=';'
    for i in $arg_list; do
      IFS="$save_IFS"
      echo "$i"
    done
    IFS="$save_IFS"
    

    Note that every expanded argument is printed individually.

    $ ./test.sh
    hello world
    have a nice day
    
    0 讨论(0)
  • 2020-12-01 21:51

    I don't think it is doing what you think it is doing.

    [~]$ myArg="\"hello\" \"world\""
    [~]$ echo "string is:" $myArg
    string is: "hello" "world"
    

    I see no extra quotes of any kind- echo gets three argument strings.

    [~]$ cargs(){ echo $#; }
    [~]$ cargs "string is:" $myArg
    3
    

    Bash will expand the variable first, so

    cargs "string is:" $myArg
    

    becomes (though without the literal backslashes- this is why string escaping is a PITA)

    cargs "string is:" "\"hello\"" "\"world\""
    

    And the args array is:

    0x00:string is:0
    0x0B:"hello"0
    0x13:"world"0
    0x1B:0
    

    Now, if you add the *, or glob path expansion in one of those, Bash will at this point expand it, unless you escape it, or use single quotes in your literal command.

    [~]$ cargs "string is:" $myArg *
    19
    [~]$ cargs "string is:" $myArg "\*"
    4
    [~]$ cargs "string is:" $myArg '*'
    4
    
    0 讨论(0)
  • 2020-12-01 21:55

    Don't use quotes, use an array (see BashFAQ #050):

    $ myArgs=("hello" "world" "multiword arg with * ?")
    + myArgs=("hello" "world" "multiword arg with * ?")
    $ echo "${myArgs[@]}"
    + echo hello world 'multiword arg with * ?'
    hello world multiword arg with * ?
    

    If it really needs to be in the form of quoted strings within a string, you're either going to have to use something like eval "echo $myArg" (which can cause some really nasty bugs, if you aren't careful) or parse it yourself (which is going to be difficult).

    0 讨论(0)
  • 2020-12-01 22:03

    If you want to pass a variable value as a parameter (99% of cases on SO), simply use proper quoting:

    arg="foo bar"
    command "$arg"
    

    If you want to pass several arguments, use arrays:

    args=("foo bar" "baz ban" bay)
    command "${args[@]}"
    
    0 讨论(0)
提交回复
热议问题