How to loop through space separated values?

How do I loop thru space separated values in a variable?
I hate to use very complicated counter increment logic for this kind of simple problem.

Expected result(using ksh)

$>echo "aaa bbbb cccc" | <looping code here>
var=aaa
var=bbbb
var=cccc
$>echo "aaa bbbb cccc" | while IFS=" " read var; do echo "var=$var"; done
var=aaa bbbb cccc
$>echo "aaa bbbb cccc" | while IFS=' ' read var; do echo "var=$var"; done
var=aaa bbbb cccc
$>echo "aaa bbbb cccc" | while IFS=\  read var; do echo "var=$var"; done 
var=aaa bbbb cccc
$>echo "aaa bbbb cccc" | while IFS="\ " read var; do echo "var=$var"; done
var=aaa bbbb cccc
% printf 'var=%s\n' aaa bbbb cccc  
var=aaa
var=bbbb
var=cccc

If you really need a loop for some reason:

% set -- aaa bbbb cccc 
% for w; do printf 'var=%s\n' "$w"; done
var=aaa
var=bbbb
var=cccc

Note that set -- will reset your positional parameters (i.e. you'll loose them).

By the way, what exactly are you trying to achieve?

Here is some ideas

a=$(echo "aaa bbbb cccc"   )
set -- $a
while [ $# -gt 0 ]
do
        echo "var=$1"
        shift
done

#####
arr=( $(echo "aaa bbb ccc") )
while [ ${#arr[@]} -gt 0 ]
do
        echo "var=${arr[0]}"
        set -A arr -- ${arr[@]:1}
done

####
echo aaa bbb ccc | some.sh

#some.sh:
while [ $# -gt 0 ]
do
        echo "var=$1"
        shift
done

I think this is being overthought somewhat...

var="string with spaces"
for X in $var # note that $var must NOT be quoted here!
do
        echo "$X"
done
1 Like

I am using KSH version M-11/16/88i. Following command works only when there are no quotes around variables. I don't think I can use it in my case..

I am trying to process sets of files[ file1 file2 ..] [ passed as a arguments from first loop, and process each file in second loop.

SAP_A='/<folderA>/SapRFCLogs_A.*'   # This will resolve to few files
SAP_B='/<folderB>/SapRFCLogs_B.*'    # This will resolve to few files

set -A RFC_Fldrs "SAP_A" "SAP_B"

for file in "${RFC_Fldrs[@]}"
do
        vTemp=$(eval echo \$$file)   # this will pass underlying array variable values to vTemp.
       
        # This line will go into function call once command works..<functioncall> <$vTemp>
         echo $vTemp | while IFS=" " read file1; do echo $file1; done     # Why this IFS=" " does not work here!
done

About other solutions with code more than 3 lines.
I can't believe we have to reinvent the wheel for such a simple task by writing 25 lines of code.. I will be ashamed of using Shells..

Your question was phrased a little awkwardly. You got what you asked for, but perhaps not what you wanted -- I don't see a reason why you actually need to use a pipe there at all. The pipe is what's making it so complicated.

Given that, did you try my solution?

var="string with spaces"
# This kind of string splitting is controlled by IFS too!
for X in $var # note that $var must NOT be quoted here!
do
        echo "$X"
done
for file in '/<folderA>/SapRFCLogs_A.*'  '/<folderB>/SapRFCLogs_B.*'
do
        for f in $file
        do
                echo $f
        done
done

Modifying your loop:

SAP_A='/<folderA>/SapRFCLogs_A.*'   # This will resolve to few files
SAP_B='/<folderB>/SapRFCLogs_B.*'    # This will resolve to few files

for file in RFC_Fldrs "SAP_A" "SAP_B"
do
        # You may also be able to do "${!file}" depending on your shell.
        # Best to avoid eval if you can!
        vTemp=$(eval echo \$$file)   # this will pass underlying array variable values to vTemp.
       
        # This line will go into function call once command works..<functioncall> <$vTemp>
        for X in $vTemp
        do
                echo $X
        done
        # Why this IFS=" " does not work here!
        # Because 'read' reads lines, not individual fields.
done

Of course :slight_smile:

What's wrong with:

SAP_A='/<folderA>/SapRFCLogs_A.*'  
SAP_B='/<folderB>/SapRFCLogs_B.*' 

for f in $SAP_A $SAP_B; do
  printf '%s\n' "$f"
done

Which of course could be simply written as (assuming the filenames don't contain embedded newlines):

SAP_A='/<folderA>/SapRFCLogs_A.*'  
SAP_B='/<folderB>/SapRFCLogs_B.*' 

export SAP_A SAP_B

(
  IFS='
'
  printf '%s\n' $SAP_A $SAP_B
  ) 

Sorry, I did not check for loop before posting. I had some wrong assumptions about it.

For loop works great for this.

var='aa bb cc"   # Notice this one has quotes.
for str in $(echo $var); do 
  echo $str
done
output:
aa
bb
cc

kchinnam,
what we're trying to say is that you need neither a subshell $( ... ) nor the first echo command in this case. This code is more correct and concise:

var='aa bb cc'

for str in $var; do    
  printf '%s\n' "$str" 
done

You need to quote the variable str in order to prevent shell globbing (or some other special character expansion).
I'd recommend the printf builtin command instead of echo for greater portability (and flexibility).

The $( ... ) are wholly useless. The example I gave you originally works.

var='aa bb cc'
for str in $var
do
   echo "$str"
done