Using read to assign value to bash variable not working

Hi,

I am attempting to assign the output of the following command, to two bash variables, var1 and var2 using "read," but it doesn't seem to be working.

[root@xxx ~]# openstack hypervisor stats show | awk -F'|' 'NR==14{print $2,$3}'
 vcpus                  92

[root@xxx ~]# echo $?
0

[root@xxx ~]# openstack hypervisor stats show | awk -F'|' 'NR==14{print $2,$3}' | read var1 var2

[root@xxx ~]# echo $var1

[root@xxx ~]# echo $var2

Could I get some guidance around what is happening here?

I'm familiar with using var1=$(awk ...) to assign output to a bash variable, but wanted to see how it's done with read.

Thanks.

This is because commands within a pipeline are run in subshells so the read statement is setting the variables is a subshell which has not impact on the main shell.

You can achieve what you want using process substitution like this:

# read var1 var2 < <(openstack hypervisor stats show | awk -F'|' 'NR==14{print $2,$3}')
# echo $var1
vcpus

Edit:
Also in bash 4.* and later you can use a shell option to run the last pipeline command in the current shell.
Note this only work for shells without job control, so in an interactive shell (as opposed to a script) you will also need turn off job control ( set +m ).

# echo $BASH_VERSION
5.0.7(1)-release
# shopt -s lastpipe
# set +m

# echo A B C | head -1 | read first second rest
# echo $first
A

# set -m
# shopt -u lastpipe
2 Likes

Hi Chubler_XL,

Appreciate the clarification.

What is the purpose of two "<" ? Does it mean that each value from awk will be assigned to the bash variable, with whitespace as delimiter?

Thanks.

the first < is a standard input redirection and causes input to the read command to come from a file.

The second part is process substitution witch takes the format of <(list) . The value list can be a command or a pipeline of commands which is executed and the output is a file name of a named pipe that contains the output of list .

2 Likes

Here are some more alternatives to try:

Use a here string

read var1 var2 <<< "$(openstack hypervisor stats show | awk -F'|' 'NR==14{print $2,$3}')"

Use a here document

read var1 var2 << EOB
  $(openstack hypervisor stats show | awk -F'|' 'NR==14{print $2,$3}')
EOB

Use a code block (the variables can be used inside the code block)

openstack hypervisor stats show | awk -F'|' 'NR==14{print $2,$3}' |
{
  read var1 var2
  echo "$var1"
  echo "$var2"
}

Use the if statement as block and test if the variables are being read (the variables can be used inside the if statement).

openstack hypervisor stats show | awk -F'|' 'NR==14{print $2,$3}' |
if read var1 var2; then
  echo "$var1"
  echo "$var2"
fi
1 Like