Given a function that modifies a global variable and outputs something on stdout:
global_variable=old_value
myfunction() {
global_variable=new_value
echo some output
}
In ksh93 or mksh R45 or newer you can use:
var=${
myfunction
}
Then:
$ print -r -- "$global_variable, $var"
new_value, some output
${ ...; } is a form of command substitution that doesn't spawn a subshell. For commands that are builtin commands, instead of having them writing their output to a pipe (for which you'd need different processes to read and write on the pipe to avoid dead-locks), ksh93 just makes them not output anything but gather what they would have been outputting in to make up the expansion. mksh uses a temporary file instead.
$ ksh -c 'a=${ b=123; echo foo;}; print -r -- "$a $b"'
foo 123
fish's command substitution also behaves like ksh93's ${ ...; }:
$ fish -c 'set a (set b 123; echo foo); echo $a $b'
foo 123
In most other shells, you'd use a temporary file:
myfunction > file
var=$(cat file) # can be optimised to $(<file) with some shells
On Linux, and with bash 4.4 or older or zsh (that use temp files for <<<), you can do:
{
myfunction > /dev/fd/3 &&
var=$(cat<&3)
} 3<<< ''
In zsh, you can also do:
() {
myfunction > $1
var=$(<$1)
} =(:)
In Korn-like shells such as ksh, zsh or bash, command substitution, whether the $(cmd...) standard form or the $(<file) or ${ cmd...; } variants strip all trailing newline characters (from file or the output of cmd). See shell: keep trailing newlines ('\n') in command substitution for how to work around that.
In fish, set var (cmd) assigns each line of the output of cmd to separate elements of the $var array. $var will contain the same thing whether cmd outputs foo or foo<newline>. Since version 3.4.0, fish also supports set var "$(cmd)" which behaves like in Korn-like shells (removes all trailing newline characters).
myvarsupposed to contain? Could you give an example with a real command and explain what output you want to save? And what do you have against subshells anyway? – terdon Jan 17 '17 at 10:22$myvardoes not containfooin my examples. After all,fooshould be in stdin. I simplified the example on purpose. Theecho foothing is actually a more complicated command changing global variables, which won’t work if it’s in a subshell. – Parckwart Jan 17 '17 at 10:26$(</dev/stdin)creates a subshell with empty stdin. – Ipor Sircer Jan 17 '17 at 10:27myvar="foo"? if you want to assign the output of a command to a variable, then usevar=$(command). There's nothing wrong with that (in fact, it is the one correct way of doing it). – terdon Jan 17 '17 at 10:27echo foo | echo $(</dev/stdin)work then? – Parckwart Jan 17 '17 at 10:29echois a command that can read from stdin. It isn't a variable. You are comparing apples to oranges. – terdon Jan 17 '17 at 10:53myvar=$(complex_function)the function is in a subshell. Withcomplex_function | myvar=$(</dev/stdin)it’s not. – Parckwart Jan 17 '17 at 10:54man bash. Just give us a complete example and we can help you out. – terdon Jan 17 '17 at 10:57