28

In bash, I know that it is possible to write a for loop in which some loop control variable i iterates over specified integers. For example, I can write a bash shell script that prints the integers between 1 and 10:

#!/bin/bash

for i in {1..10}
do
 echo $i
done

Is it possible to instead iterate over a loop control variable that is a string, if I provide a list of strings? For example, suppose that I have a string fname that represents a file name. I want to call a set of commands for each file name. For example, I might want to print the contents of fname using a command like this:

#!/bin/bash

for fname in {"a.txt", "b.txt", "c.txt"}
do
 echo $fname
done

In other words, on the first iteration, fname should have the value fname="a.txt", while on the second iteration, fname should have the value fname="b.txt", and so on. Unfortunately, it seems that the above syntax is not quite correct. I would like to obtain the output:

a.txt

b.txt

c.txt

but when I try the above code, I obtain this output:

{a.txt,

b.txt,

c.txt}

Can you please help me determine the correct syntax, so that I can iteratively change the value/contents of the variable fname? Thank you for your time.

2
  • 6
    Remove the {}, you don't need anything to loop over a (space-delimited) list
    – Mat
    Sep 8, 2012 at 15:54
  • 4
    @Mat means remove the {} and the ,s. The alternative is to remove the spaces. So either "a.txt" "b.txt" "c.txt" or {"a.txt","b.txt","c.txt"}. But I prefer {a..c}.txt instead.
    – manatwork
    Sep 8, 2012 at 16:20

3 Answers 3

44

The correct syntax is as follows:

#!/bin/bash

for fname in a.txt b.txt c.txt
do
  echo $fname
done
6
  • 9
    Also, assuming an array of names fnames=( a.txt b.txt c.txt ) you can use the syntax for f in ${fnames[@]}; do echo $f; done.
    – user13742
    Sep 8, 2012 at 19:12
  • 1
    Is it true that for fname in a.txt b.txt c.txt and for fname in "a.txt" "b.txt" "c.txt" yield identical results?
    – Andrew
    Sep 8, 2012 at 19:39
  • Andrew, yes it is true. They will yield identical results
    – Ali Gangji
    Sep 8, 2012 at 20:29
  • 1
    Of course you should use for f in "${fnames[@]}"; do echo $f; done (with quotes around ${fnames[@]}) if the fnames values might contain whitespace.  And you should use "$f", especially if you're doing anything more sophisticated than echo (e.g., cat or cp). (And even if you're only doing echo, you should use printf instead.) Apr 23, 2016 at 21:02
  • I think @user13742 should be also noted in the answer. Jan 13, 2018 at 4:53
0

Seems to me you should just do...

printf %s.txt\\n a b c
1
  • I like this even though the OP likely had something in mind to do other than echo before he was done.
    – Elder Geek
    Feb 4, 2016 at 18:03
0

As noted by user13742 in the comments, we can make use of arrays in bash and ksh:

#!/usr/bin/env bash

files_list=( "a.txt" "b.txt" "c and space.txt" )

for i in "${files_list[@]}"
do
    echo "$i"
    # do something else here,maybe
done

And works as so:

$ ./iterate_files_array.sh                                                      
a.txt
b.txt
c and space.txt

However, some shells such as dash ( /bin/sh on Ubuntu ) don't support arrays. In such case we could resort to using here-document structure: <<

#!/bin/sh

while IFS= read -r line
do
    echo "$line"
done << EOL
one.txt
two.txt
with space.txt
EOL

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .