I run across this quite a bit and sort of do a “tsk-tsk” to the perpetrator. Greg of yesthatsright.net suggested I make a post about it.
Let us assume you need to perform an operation on a bunch of files. I typically see it done as so in the BASH interpretor:
for I in `ls *.sh`
do
something
done
Now, performing the backtick (`) subshell generally causes some hard to handle data mangling issues. Most commonly a space in the file name or special character will result in odd permutations of ${I}. For example in a file listing such as:
file1.sh
file2.sh
file three.sh
Your resulting loop will end up with:
[bdowney@tlfmgt1 ~]$ for I in `ls *.sh`; do echo ${I}; done
file1.sh
file2.sh
file
three.sh
The subshell returns strings to `for’ which interprets whitespace as a new loop iteration. This obviously causes issues for your loop logic, and I have seen people build in some pretty elaborate methods to handle it. But it’s all for not–since `for’ is a reserved shell function, it inherently understands file globbing. Thus:
[bdowney@tlfmgt1 ~]$ for I in *.sh; do echo ${I}; done
file1.sh
file2.sh
file three.sh
Is all you need to do and solve your problem. But what if one has a list of filenames in a file, or needs to pass more arguments to provide a better list of said files (for example, ls -t?). Not to worry, the BASH built-in `read’ to the rescue!
[bdowney@tlfmgt1 ~]$ ls -tr *.sh | while read I; do echo ${I}; done
file1.sh
file2.sh
file three.sh
And as you’d expect, works the same when redirecting STDIN:
[bdowney@tlfmgt1 ~]$while read I; do echo ${I}; done < input.file
So stop wasting those extra shell processes!


I uncovered the differences between ‘for’ and the ‘while-read-do’ loop while writing a script some time ago. Caused me a lot of heartburn! Happy Globbing!
Hello, nice linux related posts going on here
I’ve always put inverted commas around the list part and the variable, like so:
#!/bin/bash
for I in “$( ls -rt *.sh )”
do
echo “$I”
done
[user@server ~]$ for I in “$( ls -rt *.txt )” ; do echo “$I”; done
fileone.txt
filetwo.txt
file three.txt
I wasn’t aware of the file globbing properties of “for”; thanks for that
Take ‘er easy,
MrKane
ps. I distrust backquotes, and so use “$()” instead