while read -d $'\0' file; do
found=yes
echo "Modifying $file"
chmod 755 "$file"
done < <(find /data -type f -perm 400 -print0)
if [ "x$found" != "xyes" ]; then
echo "No files found to modify"
fi
This uses the process substitution feature in Bash. It's equivalent to
find ... | while read ...
except in that case, the while read is performed in a subshell, so we can't set variables that will be seen in the outer shell. Instead, we can use process substitution. <(cmd) runs cmd in a subshell, with its standard output redirected into a named pipe. The name of that pipe is substituted into the outer command.
We then use < to redirect from this pipe into standard input of the while read command, which reads each delimited record in turn, and stores the value in the name specified (file in this case). By default, read breaks on newlines. For most files, that would be fine; you could do:
while read file; do
...
done < <(find /data -type f -perm 400)
and it would work fine. But it is technically possible to have a newline in a filename, in which case that would break. The -print0 argument to find, and -d $'\0' argument to read, causes them each to use a null character as a delimiter, which is not valid in a filename.
find /data -type f -perm 400 -exec chmod -v 755 \{\}? Oh, you'll be missing the "No files to modify" message in case there's no match, but is that really a problem?