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).
myvar
supposed 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$myvar
does not containfoo
in my examples. After all,foo
should be in stdin. I simplified the example on purpose. Theecho foo
thing 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:29echo
is 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