0

Take the following script:

#!/bin/bash

function print_args() {
    arg_index=1
    while [ $# -gt 0 ]; do
        echo "$arg_index: $1"
        arg_index=$(expr $arg_index + 1)
        shift
    done
    echo
}

echo "print_args foo bar=\"baz qux\""
echo "-----------------------------------------------"
print_args foo bar="baz qux"

args="foo bar=\"baz qux\""

echo "print_args \$args (args=\"foo bar=\\\"baz qux\\\"\")"
echo "-----------------------------------------------"
print_args $args

echo "print_args \"\$args\" (args=\"foo bar=\\\"baz qux\\\"\")"
echo "-----------------------------------------------"
print_args "$args"

It outputs the following:

print_args foo bar="baz qux"
-----------------------------------------------
1: foo
2: bar=baz qux

print_args $args (args="foo bar=\"baz qux\"")
-----------------------------------------------
1: foo
2: bar="baz
3: qux"

print_args "$args" (args="foo bar=\"baz qux\"")
-----------------------------------------------
1: foo bar="baz qux"

The output I want to get is the following:

-----------------------------------------------
1: foo
2: bar="baz qux"

This is the result of print_args foo bar="baz quz". However, I need it to be the result of calling print_args with a single variable argument. I am ultimately trying to figure out how to pass multiple arguments to CMake within a shell script that is set up to run

cmake ${cmake_flags} ../${target}

Some of the options in cmake_flags need to be quoted because they contain spaces, but I overall want CMake to recognize multiple different options being passed to it, which doesn't happen if I quote cmake_flags.

Jon McClung
  • 1,619
  • 20
  • 28
  • 1
    Aside: `arg_index=$(expr $arg_index + 1)` is an **extremely** inefficient (and nonportable -- `$(( ))` is guaranteed to be part of any POSIX-compliant shell, whereas `expr` is a separate tool your OS may or may not provide) way to write `arg_index=$(( arg_index + 1 ))`. Also see http://wiki.bash-hackers.org/scripting/obsolete re: the `function` keyword, especially when combined with `()`s. – Charles Duffy Oct 05 '18 at 21:25
  • 1
    ...as to the real question, though, [BashFAQ #50](http://mywiki.wooledge.org/BashFAQ/050) is very pertinent. Is there a reason you *want* that specific calling convention, or would you be willing to accept a different one that accomplished the same goal? – Charles Duffy Oct 05 '18 at 21:26
  • `print_args foo 'bar="baz qux"'` use single quotes – karakfa Oct 05 '18 at 21:29
  • @karakfa, ...you're assuming that the OP knows what they're doing. If they want an equivalent to `cmake foo bar="baz qux"` (in which context the quotes are syntactic rather than literal, and the actual string for the last argument is `bar=baz qux` after the shell has performed quote removal and put it on `cmake`'s argument vector), those literal quotes would be quite undesired. – Charles Duffy Oct 05 '18 at 21:31
  • 1
    @Jon McClung, ...so, if you run `cmake foo bar="baz qux"` in a POSIX-compliant shell, as far as `cmake` can tell it got the argument vector (in C syntax) `char[][]{"cmake", "foo", "bar=baz qux", NULL}`. There are no literal quotes in that at all; the quotes in your original shell command were just instructions to the shell about how *the shell* should parse the enclosed substring into a literal C string, not instructions to `cmake`. – Charles Duffy Oct 05 '18 at 21:34
  • Yes, right. I just answered the narrow question disregarding what OP really needs. – karakfa Oct 05 '18 at 21:35
  • @CharlesDuffy Thank you for helping me improve! Hopefully I'll be able to use this method to solve my real problem. I can't help but smile at "...you're assuming that the OP knows what they're doing." That's never a safe assumption, is it? ;) – Jon McClung Oct 05 '18 at 21:40
  • 2
    One thing that helps re: figuring out what's going on under the hood is running `set -x` to enable logging; that will print commands as the shell sees them before they're run, so if you run `cmake foo bar="baz qux"` the log might be something like `cmake foo 'bar=baz qux'`. – Charles Duffy Oct 05 '18 at 21:43
  • 1
    One warning about `set -x`: it prints something *equivalent* to the command being executed, but not necessarily what you'd expect. For instance, the commands `somecmd 'quote: "'`, `somecmd "quote: \""`, `somecmd $'quote: "'`, and `somecmd quote:\ \"` are all equivalent (i.e. they do exactly the same thing), so the shell will print the same thing for all of them, no matter which you actually entered. – Gordon Davisson Oct 06 '18 at 00:16

1 Answers1

1

Use array syntax instead, as follows:

cmake_flags=( foo bar="baz qux" )

cmake "${cmake_flags[@]}"
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441