Linux Bash: Multiple Variable Assignment

Linux bash: Multiple variable assignment

First thing that comes into my mind:

read -r a b c <<<$(echo 1 2 3) ; echo "$a|$b|$c"

output is, unsurprisingly

1|2|3

Bash: How to split a string and assign multiple variables

x="http://web.com/sub1/sub2/sub3/sub4/sub5/sub6"
IFS="/" read -r foo foo foo foo var1 foo var2 var3 foo <<< "$x"
echo "$var1 $var2 $var3"

Output:


sub2 sub4 sub5

Or with an array:

x="http://web.com/sub1/sub2/sub3/sub4/sub5/sub6"
IFS="/" read -r -a var <<< "$x"
echo "${var[4]}"
declare -p var

Output:


sub2
declare -a var='([0]="http:" [1]="" [2]="web.com" [3]="sub1" [4]="sub2" [5]="sub3" [6]="sub4" [7]="sub5" [8]="sub6")'

From man bash:

IFS: The Internal Field Separator that is used for word splitting after expansion and to split lines into words with the read builtin command.

Bash multiple variable assignment

The output of curl contains some \r characters,
that's why the output looks messed up.
You can get rid of it by inserting a tr -d '\r' into the pipeline after the curl and before the egrep.

Is it really important to read into RESP and DATE variables?
You could use Awk to extract the interesting parts simpler, saner,
and output directly in the desired format:

curl ... | tr -d '\r' | awk '/^< Date: / { date = substr($0, 9); print "[" date "] " resp } /^< HTTP\// { resp = $3 }'

How to read variables from file, with multiple variables per line?

I think all you're looking for is to read multiple variables per line: the read command can assign words to variables by itself.

while read -r first second third; do
do_stuff_with "$first"
do_stuff_with "$second"
do_stuff_with "$third"
done < ./test.txt

using jq to assign multiple output variables

You can use separate variables with read :

read var1 var2 var3 < <(echo $(curl -s 'https://api.github.com/repos/torvalds/linux' | 
jq -r '.id, .name, .full_name'))

echo "id : $var1"
echo "name : $var2"
echo "full_name : $var3"

Using array :

read -a arr < <(echo $(curl -s 'https://api.github.com/repos/torvalds/linux' | 
jq -r '.id, .name, .full_name'))

echo "id : ${arr[0]}"
echo "name : ${arr[1]}"
echo "full_name : ${arr[2]}"

Also you can split jq output with some character :

IFS='|' read var1 var2 var3 var4 < <(curl '......' | jq -r '.data | 
map([.absoluteNumber, .airedEpisodeNumber, .episodeName, .overview] |
join("|")) | join("\n")')

Or use an array like :

set -f; IFS='|' data=($(curl '......' | jq -r '.data | 
map([.absoluteNumber, .airedEpisodeNumber, .episodeName, .overview] |
join("|")) | join("\n")')); set +f

absoluteNumber, airedEpisodeNumber, episodeName & overview are respectively ${data[0]}, ${data[1]}, ${data[2]}, ${data[3]}. set -f and set +f are used to respectively disable & enable globbing.

For the jq part, all your required fields are mapped and delimited with a '|' character with join("|")

If your are using jq < 1.5, you'll have to convert Number to String with tostring for each Number fields eg:

IFS='|' read var1 var2 var3 var4 < <(curl '......' | jq -r '.data | 
map([.absoluteNumber|tostring, .airedEpisodeNumber|tostring, .episodeName, .overview] |
join("|")) | join("\n")')

Echo multiple variables via single command in Bash

It'd probably be easier to use an array instead of numbered variables:

my_web=(
"some value1"
"some value2"
"some value3"
)

Then to print them like you want:

(IFS=$'\n'; echo "web at ${my_web[*]:0:3}")

This temporarily sets the "internal field separator" to a newline so that when we join the array elements (my_web[*]), it joins them on the newline. I'm also explicitly selecting the first three elements, but you don't actually need to do that in this case since those are the only elements that exist.

Note that Bash arrays are 0-indexed.

Due credit to Glenn Jackman's now-deleted answer for inspiring this echo command.

How to assign multiple variables to a FIXED sized table output

As you are relying on the word splitting in the read command,
succesive empty values are put together to cause inconsistency in the result.

Would you please try instead:

# no changes in your original template
template="General;%OverallBitRate/String%|
Video;%Width%|%Height%|%FrameRate/String%|%DisplayAspectRatio/String%|%ScanType/String%|%FrameRate/String%|%ChromaSubsampling/String%|%BitDepth%|%InternetMediaType%|%Format/String%|%Format_Profile%|%Format_Settings%|%BitRate_Mode/String%|%BitRate_Nominal/String%|%BitRate_Maximum/String%|%ColorSpace%|
Audio;%BitRate/String%|%Format/String%|%Channel(s)/String%|%BitRate_Mode/String%|%BitRate/String%|%SamplingRate/String%"

mapfile -t info < <(mediainfo --Output="$template" "$1" | sed 's/video\///g' | tr '|' '\n' | awk '{ print $1 }')

for i in "${info[@]}"; do
echo "$i"
done

The mapfile built-in command reads lines from the standard input
assigning an array (info here) to each lines.
It preserves the empty line as is then the result has always the same length.
If you want to assign individual scalar variables to the elements of the array,
you can say something like:

A="${info[0]}"
B="${info[1]}"
C="${info[2]}"
...

although it would be more convenient to treat the array as an array.

Check if multiple Bash variable are empty/not set and run this or that

Use just -z $VAR

if [[ -z $VAR1 || -z $VAR2 ]]; then
echo "VARs NOT set -- "
cat <<EOF > file
1
2
3
EOF
else
echo "VARs are set"
cat <<EOF > file
1
2
3
4
5
EOF
fi


Related Topics



Leave a reply



Submit