Bash foreach loop examples for Linux / Unix

See all GNU/Linux related FAQ
I used foreach on a Unix operating system and csh shell loop. Now, I am a Linux operating system. How do I use foreach loop in bash shell running on Linux?

Tutorial details
Difficulty level Easy
Root privileges No
Requirements None
Est. reading time 2 minutes
The C shell (csh) or the improved version, tcsh is a Unix shell from the late 1970s. The csh foreach loop syntax is as follows:

foreach n ( 1 2 3 4 5 )

Linux foreach tcsh example
However, bash lacks foreach syntax; instead, you can use bash while loop or bash for loop syntax as described below.

Bash foreach loop examples

Let us say you want to convert the following csh forloop example:

foreach i ( * )
echo "Working $i filename ..."

Unix foreach tcsh example
Above csh or tcsh foreach displayed a list of files using loop. Here is similar code in a bash shell:

for i in *
  echo "Working on $i file..."

Bash foreach loop example
However, one can find and safely handle file names containing newlines, spaces, special characters using the find command

## tested on GNU/Linux find ##
## and bsd/find only ##
find /dir/ -print0 | xargs -r0 command
find /tmp/test -print0 | xargs -I {} -r0 echo "Working on "{}" file ..."
find /tmp/test -type f -print0 | xargs -I {} -r0 echo "Working on '{}' file ..."
Working on '/tmp/test' file ...
Working on '/tmp/test/hosts.deny' file ...
Working on '/tmp/test/My Resume.pdf' file ...
Working on '/tmp/test/hostname' file ...
Working on '/tmp/test/hosts.allow' file ...
Working on '/tmp/test/Another   file     name.txt' file ...
Working on '/tmp/test/resolv.conf' file ...
Working on '/tmp/test/hosts' file ...
Working on '/tmp/test/host.conf' file ...

Howto use foreach in bash shell

Say you have a file named lists.txt as follows:
cat lists.txt
Sample outputs:


Each in there is a file located on your Unix or Linux server. Here is how to read lists.txt file and work on each file listed in lists.txt:

for n in $(cat lists.txt )
    echo "Working on $n file name now"
    # do something on $n below, say count line numbers
    # wc -l "$n"

Although for loop seems easy to use for reading the file, it has some problems. Don’t try to use “for” to read file line by line in Linux or Unix. Instead, use while loop as follows:

## path to input file 
## Let us read a file line-by-line using while loop ##
while IFS= read -r line
  printf 'Working on %s file...\n' "$line"
done < "$input"
Foreach loop in bash

🥺 Was this helpful? Please add a comment to show your appreciation or feedback.

nixCrat Tux Pixel Penguin
Hi! 🤠
I'm Vivek Gite, and I write about Linux, macOS, Unix, IT, programming, infosec, and open source. Subscribe to my RSS feed or email newsletter for updates.

3 comments… add one
  • Jay Aug 18, 2020 @ 19:05

    How would one do that example command on a single line command in MacOS’ terminal? Tried remove the line breaks and tabs and then it becomes non-functional. Tried adding some \newline s even and it still didn’t work.

  • Rob Apr 15, 2021 @ 18:17

    My issue when going from tcsh to bash is that if you use a command in the loop that is capable of *optionally* taking STDIN *if* it is present, the loop stops if you are using the contents of the file as the loop items. tcsh does not have this problem.

    Let’s say we have a command called that can operate on a given file name, but if STDIN is present, will take STDIN instead and ignore the supplied files. In that instance, this tcsh loop has no problem what-so-ever:

    foreach f ( `cat filelist.txt` )
      optin $f

    However, if you want to do that in bash, using a while loop as suggested, there’s a loose canon of an input stream available to the commands inside the loop to consume, so:

    while IFS= read -r line
    do "$line"
    done < filelist.txt

    Then output all except the first line of filelist.txt and the loop only executes 1 iteration.

    This caught me by surprise when I first started learning bash, trying to do what I normally would do in tcsh. And for the life of me, I cannot figure out 1 use-case why you would supply the loop items of the standard input to the commands inside the loop.

    Personally, to me, having used tcsh for so long, it seems sloppy to allow the stream of input to the loop controls to be available to the commands inside the loop.

    Sure, bash has a lot of extras that make it better, but this one issue has always bothered me. I would be interested in hearing how you deal with this situation. All of the scripts I have written over the years while being a tcsh user optionally take STDIN if it is present and/or takes explicitly supplied files.

    • 🛡️ Vivek Gite (Author and Admin) Vivek Gite Apr 16, 2021 @ 3:57

      Instead of:

      while IFS= read -r line
      do "$line"
      done < filelist.txt


      while IFS= read -r line
        echo "$line"
      done < "${1:-/dev/stdin}"

      Now we can run it as to read list from filelist.txt

      ./script filelist.txt

      This will read from STDIN


      I hope this helps!

Leave a Reply

Your email address will not be published. Required fields are marked *

Use HTML <pre>...</pre> for code samples. Your comment will appear only after approval by the site admin.