30

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.

asked Sep 8, 2012 at 15:50
2
  • 6
    Remove the {}, you don't need anything to loop over a (space-delimited) list Commented 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. Commented Sep 8, 2012 at 16:20

3 Answers 3

46

The correct syntax is as follows:

#!/bin/bash
for fname in a.txt b.txt c.txt
do
 echo $fname
done
Michael Mrozek
95.6k40 gold badges245 silver badges236 bronze badges
answered Sep 8, 2012 at 16:48
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. Commented 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? Commented Sep 8, 2012 at 19:39
  • Andrew, yes it is true. They will yield identical results Commented 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.) Commented Apr 23, 2016 at 21:02
  • I think @user13742 should be also noted in the answer. Commented Jan 13, 2018 at 4:53
0

Seems to me you should just do...

printf %s.txt\\n a b c
answered Feb 13, 2015 at 7:35
1
  • I like this even though the OP likely had something in mind to do other than echo before he was done. Commented 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
answered Nov 12, 2017 at 22:34

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.