1
for X in $(find ~/Documents/ -type f);do date -r "${X}";done

The above line works fine when the filenames in "/Documents/" contain no space.
However, if the filenames contain a space, the following error will arise:

 No such file or directory

How can I make it work for filenames containing a space?

3 Answers3

4

Don't use a loop, use the -exec argument of find:

find ~/Documents/ -type f -exec date -r {} \;
choroba
  • 47,233
2

Yes. That is one of the well known problems of using find and a loop.

One simple way to solve it is to dump the found list into stdout and read it:

find ~/Documents/ -type f |
while IFS= read -r filename
do
    date -r "$filename"    # ... or any other command using $filename
done

If your command is small enough, you can just use -exec key of find:

find ~/Documents/ -type f -exec date -r '{}' \;
Chris Davies
  • 116,213
  • 16
  • 160
  • 287
White Owl
  • 5,129
2

You can't, which is one of the reasons why you never use for that way to loop over the output of a command that returns file names. Also known as Bash Pitfall Number 1. If you use a while loop instead, you will handle files with spaces just fine:

$ ls
'a file with spaces'
$ find . -type f | while read -r X; do date -r "$X"; done
Fri May 12 04:51:42 PM BST 2023

However, that will still fail on file names that contain newlines:

$ touch "$(printf 'a file with\na newline')"
$ ls
'a file with'$'\n''a newline'  'a file with spaces'
$ find . -type f | while read -r X; do date -r "$X"; done
date: './a file with': No such file or directory
date: 'a newline': No such file or directory
Fri May 12 04:51:42 PM BST 2023

To get around that, and assuming your find implementation supports it, you can use -print0 to print null-terminated lines, and then use a loop that uses the NUL byte as a separator. Like this:

$ find . -type f -print0 | while IFS= read -r -d '' X; do date -r "$X"; done
Fri May 12 04:53:06 PM BST 2023
Fri May 12 04:51:42 PM BST 2023

That said, by far the best approach is to use find's -exec, which unlike -print0 is POSIX and portable, and also can handle arbitrary file names just fine:

$ find . -type f -exec date -r {} \;
Fri May 12 04:53:06 PM BST 2023
Fri May 12 04:51:42 PM BST 2023
terdon
  • 242,166