1
variable_list="
 any:any:-a -b -c any
 one:one:-c -b -f -m mul
 mul:one:-c -b -f -m mul
"
for f in `echo $variable_list`
do
  c1=`echo $f | cut -d':' -f1`;
  c2=`echo $f | cut -d':' -f2`;
  c3=`echo $f | cut -d':' -f3-`;
  echo "c1==>$c1 and c2==>$c2 and c3==>$c3";
  #exit 0; ###I made mistake here
done;

Expected Output:

c1==>any and c2==>any and c3==>-a -b -c any
c1==>one and c2==>one and c3==>-c -b -f -m mul
c1==>mul and c2==>one and c3==>-c -b -f -m mul

Edit 1:

I realized that I was stupid while using the script and at first iteration I used exit 0 to test it only first line since I have lots of this in real. It was working as it has to be.

Can I achieve the mentioned output by maintaining the variable_list with out modifying the format/way of input?

(I am using bash)

RBB
  • 1,009

2 Answers2

5

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:

Kusalananda
  • 333,661
0

You can use awk to get your output :

echo "$variable_list" | awk -F: '
{
  sub("^ ","")
  for(i=1;i<=NF;i++)
    sub(/^/,"c" i "==>",$i)
}1' OFS=" and "
ctac_
  • 1,960