find | while read

Stuart Jansen sjansen at buscaluz.org
Sat Apr 12 09:52:47 MDT 2008


Ever since I was taught "while read" as a method to avoid whitespace
problems, it has been one of my favorite shell scripting tricks.
Unfortunately, while working on a git script yesterday, I discovered an
instance where it doesn't work. Specifically, Bash is leaking the output
of find to the screen and horking stdin.

I found a workaround, but it's more complex than I like. I've included
three generations of a simplified script as an example. What I'd like to
know is, does anyone know a more sane method for looping over a list of
files produced by a command like find, git or anything else?

NOTE: To save time, let me point out that git doesn't have an equivalent
of find's --exec, so that's out. In addition, the script has to handle
whitespace in filenames so "for FILE in $( ... )" is also out. I have a
sneaking suspicion that changing $IFS could lead to a solution, but that
just freaks me out.

Any takers?

# ==================================
# Simple but doesn't work
# ==================================
find . -name '*.txt' | \
while read FILE
do
    echo Spell checking $FILE
    aspell -c "$FILE"
done
# ==================================


# ==================================
# Insane but works
# ==================================
TEMP=$(mktemp)
exec 3<>"$TEMP"
find . -name '*.txt' > "$TEMP"
while read FILE <&3
do 
    echo Spell checking $FILE
    aspell -c "$FILE"
done
exec 3>&-
rm "$TEMP"
# ==================================


# ==================================
# Insane but works and more secure
# ==================================
TEMP=$(mktemp)
exec 3<>"$TEMP"
find . -name '*.txt' > "$TEMP"
while read FILE <&3
do 
(
    exec 3>&- # Avoid leaking the FD
    echo Spell checking $FILE
    aspell -c "$FILE"
)
done
exec 3>&-
rm "$TEMP"
# ==================================





More information about the PLUG mailing list