0

I would like do something like

./call_with_options $(./get_options)

where the command call_with_options, has for example options -i and -o, and the command get_options outputs a string like

-i"first file" -i"second file" -o"some output"

i.e. it generates a set of multiple options that take arguments which can contain spaces and as such need to be quoted. I want the call above to be equivalent to executing

./call_with_options -i"first file" -i"second file" -o"some output"

effectively replacing '$(./get_options)' as-is by whatever its output is such that it can still be interpreted by the shell.

I've tried something obvious like

get_options:

#!/bin/bash
echo -i"first file" -i"second file" -o"some output"

or

#!/bin/bash
echo "-i\"first file\" -i\"second file\" -o\"some output\""

but this does not work. For only a single option it works, but once there are multiple that also can contain space I cannot figure out how to tell the call_with_options command to interpret the output correctly.

I saw various similar questions but they did not help me solve this specific problem. Something like the accepted answer of bash command output as parameters seemed relevant, but I still do not know how to handle the spaces correctly with this. Also note that xargs will not help (as far as I can tell) because I do not want to run call_with_options on each of the options, but on the whole set.

Is this somehow possible and how?

Shiwayari
  • 315
  • 3
  • 12
  • 1
    Possible? Yes. A good idea? Not at all. See [BashFAQ #50](http://mywiki.wooledge.org/BashFAQ/050). – Charles Duffy Jul 26 '19 at 21:04
  • You misunderstand what xargs does; it isn't limited to one-invocation-per-item -- by default (unless you use `-I` or `-n`), it puts as many arguments as possible on each command line. Thus, the `xargs`-based answer on the duplicate actually does what you want (with the caveat that if you want quotes to be honored, you should avoid the `-d` argument). – Charles Duffy Jul 26 '19 at 21:05
  • 1
    ...it would be much more reliable if you made your `get_options` emit NUL-delimited output (with no quoting at all); that way, there would be a precise 1:1 mapping between its possible output and the possible values a command line can represent. – Charles Duffy Jul 26 '19 at 21:08
  • 1
    ...so, let's say you did the following: `get_options() { printf '%s\0' -i"first file" -i"second file" -o"some output"; }` -- then, `readarray -d '' options < <(get_options)` will make `"${options[@]}"` a precise array of your options, so you can then call `./call_with_options "${options[@]}"` and get the exact same effect as `./call_with_options -i"first file" -i"second file" -o"some output"`. – Charles Duffy Jul 26 '19 at 21:09
  • are GNU options parsed as one when seperated by null? I have never seen that and was not aware that this is possible.. if I understand you correctly? So I would do ./call_with_options -ifirst file\0 .. etc? – Shiwayari Jul 26 '19 at 21:10
  • when a program is called on UNIX, it's passed its arguments at the operating system level as an array of C strings. All C strings have NULs at the end; that's how they're actually stored in memory. That said, no, the above code does not correctly implement my suggestion. – Charles Duffy Jul 26 '19 at 21:11
  • thanks for the quick comments, I wrote that before your elaborate answer, I'll have a closer look at that one – Shiwayari Jul 26 '19 at 21:13
  • 1
    See https://ideone.com/Vpab6G for a runnable example. – Charles Duffy Jul 26 '19 at 21:14
  • ...and in reading it, note that `"-ifirst file"` and `-i"first file"` are, as far as `call_with_options` can tell, the exact same string; the quotes are consumed by the calling shell during its parsing process, not passed to the called process. – Charles Duffy Jul 26 '19 at 21:15
  • Similarly, `printf '%s\0' -i"first file" -i"second file" -o"output file" | xargs -0 ./call_with_options` also works, with the caveat that if your argument list is too long to fit on one command line it'll split it across multiple invocations, as opposed to just failing like the array-based implementation will. (Also, just where the "too long to fit" limit is can change at runtime, as the more/larger environment variables are defined, the less space is left for command-line options; as the same block of per-process memory is used for both). – Charles Duffy Jul 26 '19 at 21:18
  • I transfered your linked code to my test code and it works just like I want. You could compile / paste it into an answer, I don't want to "steal" it by posting the same thing myself. – Shiwayari Jul 26 '19 at 21:27

0 Answers0