Reputation: 365
I've got an application that runs and defines the devices on a system. The output looks something like this:
./show-devices 192.168.1.2 | grep volume
/dev/sda volumeid-65
/dev/sdb volumeid-81
/dev/sdc volumeid-92
What I'm trying to do is run the application in a loop and assign variables like so:
sda=volumeid-65
sdb=volumeid-81
sdc=volumeid-92
Then, be able to use the $sda, $sdb, and $sdc variables later on in the script. Not all outputs are the same. Some machines will only have one volume, some will have more. All suggestions are welcome. I've tried many combinations of a for loop and don't appear to be getting anywhere. Thank you!
Upvotes: 0
Views: 3089
Reputation: 3540
How about:
eval `./show-devices 192.168.1.2 | grep volume | while read d v ;do
echo $(basename $d)=$v
done`
However, you'll not be sure of the names of the variables. So it's better to use an associative array:
# declare the array
declare -A volumes
# Assign values to the array
eval `./show-devices 192.168.1.2 | grep volume | while read d v ;do
echo volumes[$(basename $d)]=$v
done`
# Use the array
for i in "${!volumes[@]}"; do
echo "Key:$i , Value:${volumes[$i]}"
# Declare all the variables with the values as asked by question
eval $i=${volumes[$i]}
done
Explaination: | while read d v
loops over the output of the previous command reading 2 values per line. basename $d
gives me the base name of the device and $v contains the volume associated with the device. This is assigned into the volumes
associative array declared with declare -A volumes
. The while
loop runs ins a sub-shell and prints volumes[sda]=...
and eval
evaluates this in the current shell, actually assigning the value.
Usage: The for
loop is a usage example. "${!volumes[@]}"
is the list of keys for the volumes
array, and the for
loop loops over them and prints the value associated with each key in the volumes
array.
Edits:
Modified the while
loop to echo the assigment and eval
the whole thing (to get around the subshell being spawned by the pipe.
Added usage info
Added exact solution asked in question
Upvotes: 2
Reputation: 247052
source <(
./show-devices 192.168.1.2 |
sed -rn '/volume/{s#/dev/([^[:space:]]+)[[:space:]]+#\1=#;p}'
)
This runs your command, passes it through sed to format it like shell assignments, and then uses a process substitution to treat the output like a file which is sourced into the current shell.
Upvotes: 1