To answer the question in the title, the way to disable word splitting is to set IFS
to the empty string.
But what you described in the text was harder, to keep more than one multi-word string distinct after passing them through a command substitution. And there's really no simple way to do that.
The root issue here is that the result of a command substitution (~ the output to stdout of the function called within it) is just a single string (stream of bytes), and you're trying to fit multiple strings in it. In the general case, with arbitrary contents in those strings, that's a rather fundamental problem.
The also isn't too different from storing a command in a variable, just we have command substitution here instead.
A workaround would be to reserve some character to use as a separator, and set IFS
to that. With the default IFS
, you'd have space, tab and newline as such separators, which obviously doesn't work for strings with whitespace. With IFS
set to the empty string, you'd have no such separator, so you'd always get just one field.
But you could set IFS
to e.g. just the newline (assuming your strings aren't multi-line):
#!/bin/bash
IFS=$'\n'
foo() {
printf "%s\n" "$@"
}
nargs() {
echo "number of arguments nargs got: $#"
}
nargs $(foo firstarg "multi word string" "also a multi word string")
(You can't use empty strings at the end of the list, though, since the command substitution removes all trailing newlines regardless of IFS
.)
Another way is to not use the standard output of a function, but instead pass the name of a variable to the function, and have the function write to the named array via a nameref:
#!/bin/bash
bar() {
declare -n _out="$1"
shift
_out=("$@")
}
nargs() {
echo "number of arguments nargs got: $#"
}
bar tmparr firstarg "multi word string" "also a multi word string"
nargs "${tmparr[@]}"
(There's some issues with variable scoping here if a variable called _out
exists outside the function too.)
Also note that if you have unquoted expansions (variables or command substitutions), their results will also be subject to filename globbing, so an output like 12 * 34
would get badly mangled, unless you also disable globbing with set -f
.
func2
know how many argumentsfunc1
got, whenfunc1
just returns a string ? That won't be possible in any language I guess. – pLumo Mar 23 '22 at 15:58$1
not to be splitted. Your new example includes anecho
destroying any information about former aguments being split or not. – Philippos Mar 23 '22 at 16:45