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!

Recent Comments