Bash Shell list files using "for" loop
Solution 1
If you're using bash 4, just use a glob:
#!/bin/bash
shopt -s globstar
for file in **/*.txt
do
if [[ ! -f "$file" ]]
then
continue
fi
echo "$file"
# Do something else.
done
Be sure to quote "$file"
or you'll have the same problem elsewhere. **
will recursively match files and directories if you have enabled globstar
.
Solution 2
Yes, have find
separate the file names with NUL and use read
to delimit on NUL
. This will successfully iterate over any file name since NUL is not a valid character for a file name.
#!/bin/bash
while IFS= read -r -d '' file; do
echo "$file"
# Do something else.
done < <(find . -type f -name "*.txt" -print0)
Alternatively, if the # do something else
is not too complex, you can use find
's -exec
option and not have to worry about proper delimiting
user1129812
Updated on June 15, 2022Comments
-
user1129812 almost 2 years
I use the following Bash Shell script to list the ".txt" files recursively under the current directory :
#!/bin/bash for file in $( find . -type f -name "*.txt" ) do echo $file # Do something else. done
However, some of the ".txt" files under the current directory have spaces in their names, e.g. "my testing.txt". The listing becomes corrupted, e.g. "my testing.txt" is listed as
my testing.txt
It seems that the "for" loop uses "white space" (space, \n etc) to separate the file list but in my case I want to use only "\n" to separate the file list.
Is there any way I could modify this script to achieve this purpose. Any idea.
Thanks in advance.
-
user1129812 about 12 yearsThanks. But the method seems less familiar to me. I'll try it later.
-
tripleee about 12 yearsThe idiomatic use of
find
is something like this. The problem withfor file in $(find ...)
is precisely that it will split on whitespace. Instead, usefind ... | while read file
. The additional options toread
are required to properly cope with even file names with newlines, but if all you need to cope with is spaces, you can be a bit flimsier. -
user1129812 about 12 yearsThis method is a good alternative solution for my case as it allows arbitrary allowable file names. The method is now tested OK and works for my case too.
-
SiegeX about 12 years@user1129812 To add what @tripleee said, the reason why I didn't pipe the output of
find
but instead used process substitution<()
is because the latter doesn't create a subshell so any variables you might alter inside the while-loop can be accessed outside. This may be important if say you want to keep a counter of how many files you iterated through and access that counter elsewhere in the script. -
user1129812 about 12 years@SiegeX I see your point.
find ... | while read file
would leave thewhile
loop in a subshell whose variables could not be seen in the calling shell. Anyway, both solution works for my case. Thanks SiegeX and tripleee.