Filenames with spaces breaking for loop, find command
Solution 1:
Using for
with find
is the wrong approach here, see for example this writeup about the can of worms you are opening.
The recommended approach is to use find
, while
and read
as described here. Below is an example that should work for you:
find . -type f -name '*.*' -print0 |
while IFS= read -r -d '' file; do
printf '%s\n' "$file"
done
This way you delimit the filenames with null (\0
) characters, this means that variation in space and other special characters will not cause problems.
In order to update an archive with the files that find
locates, you can pass its output directly to tar
:
find . -type f -name '*.*' -printf '%p\0' |
tar --null -uf archive.tar -T -
Note that you do not have to differentiate between if the archive exists or not, tar
will handle it sensibly. Also note the use of -printf
here to avoid including the ./
bit in the archive.
Solution 2:
This works and is simpler:
find . -name '<pattern>' | while read LINE; do echo "$LINE" ; done
Credit to Rupa (https://github.com/rupa/z) for this answer.
Solution 3:
Try quoting the for
loop like this:
for FILE in "`find . -type f -name '*.*'`" # note the quotation marks
Without quotes, bash doesn't handle spaces and newlines (\n
) well at all...
Also try setting
IFS=$'\n'
Solution 4:
In addition to proper quoting, you can tell find
to use a NULL separator, and then read and process the results in a while
loop
while read -rd $'\0' file; do
something with "$file"
done < <(find . -type f -name '*.*' -print0)
This should handle any filenames that are POSIX-compliant - see man find
-print0
True; print the full file name on the standard output, followed by a null character (instead of the newline character that -print uses). This allows file
names that contain newlines or other types of white space to be correctly interpreted by programs that process the find output. This option corresponds to the
-0 option of xargs.