Your issue are with the spaces in the data. The shell will split the string into words on all spaces and the for
loop will iterate over those words.
(For a solution that does not replace variable_list
with an array, see the very end of this answer.)
Instead, use a proper array:
variable_list=(
"any:any:-a -b -c any"
"one:one:-c -b -f -m mul"
"mul:one:-c -b -f -m mul"
)
for var in "${variable_list[@]}"; do
c1=$( cut -d':' -f1 <<<"$var" )
c2=$( cut -d':' -f2 <<<"$var" )
c3=$( cut -d':' -f3- <<<"$var" )
printf 'c1==>%s and c2==>%s and c3==>%s\n' "$c1" "$c2" "$c3"
done
Using an array ensures that you can access each individual set of variables as its own array entry without relying on them being delimited by newlines or some other character.
The code is also using "here-strings" in bash
to send the string to cut
(rather than echo
and a pipe).
Or, much more efficiently,
variable_list=(
"any:any:-a -b -c any"
"one:one:-c -b -f -m mul"
"mul:one:-c -b -f -m mul"
)
for var in "${variable_list[@]}"; do
IFS=':' read -r c1 c2 c3 <<<"$var"
printf 'c1==>%s and c2==>%s and c3==>%s\n' "$c1" "$c2" "$c3"
done
Setting IFS
to a colon for read
will make read
split the input on colons (rather than on spaces, tabs and newlines).
Note that all the quotation above is significant. Without the double quotes, the shell would perform word splitting and filename globbing on the values of variable_list
, var
and the three c
variables.
Related:
If all you're after is that specific output, then you may cheat a bit:
variable_list=(
"any:any:-a -b -c any"
"one:one:-c -b -f -m mul"
"mul:one:-c -b -f -m mul"
)
( IFS=':'; set -f; printf 'c1==>%s and c2==>%s and c3==>%s\n' ${variable_list[@]} )
This runs the printf
in a subshell so that setting IFS
and the -f
(noglob
) shell option does not affect the rest of the script. Setting IFS
to a colon here will make the shell expand the unquoted variable_list
array into three sets of three arguments for printf
. printf
will print the first three according to its format string and then reuse that format for the next set of three arguments, until all arguments have been processed.
The set -f
prevents the unquoted expansion of variable_list
from triggering filename globbing, should there be any filename globbing characters in there.
Using a newline-delimited string:
variable_list="
any:any:-a -b -c any
one:one:-c -b -f -m mul
mul:one:-c -b -f -m mul"
while IFS= read -r var; do
IFS=':' read -r c1 c2 c3 <<<"$var"
printf 'c1==>%s and c2==>%s and c3==>%s\n' "$c1" "$c2" "$c3"
done <<<"$variable_list"
This reads the data from the string as if it came from a file.
Related:
cut -d: -f3 < input
works; as doescut -d: -f3- < input
– Jeff Schaller Jul 12 '18 at 14:15