I'm quite new to Linux so could do with a little help.
If there a way to make this work for all subdirectory contents rather than just the current directory?
for f in *\ *; do mv "$f" "${f// /_}"; done
With zsh:
autoload zmv # best in ~/.zshrc
zmv '(**/)(* *)' '$1${2// /_}'
Like in your code, it doesn't rename hidden files. It doesn't look inside hidden directories either. If you want to rename those, change it to:
autoload zmv # best in ~/.zshrc
zmv '(**/)(* *)(#qD)' '$1${2// /_}'
The bash equivalent (but without the safeguards provided by zmv, so you may want to add a -i option to mv) of that latter one would be:
LC_ALL=C find . -depth -name '* *' -exec bash -c '
for file do
base=${file##*/}
mv -i -- "$file" "${file%/*}${base// /_}"
done' bash {} +
There's no easy equivalent of the first one as one can't combine -prune (which would be need to not descend into hidden directories) and -depth. A functionally equivalent one could however be written as:
LC_ALL=C find . -depth -name '* *' ! -path '*/.*' -exec bash -c '
for file do
base=${file##*/}
mv -i -- "$file" "${file%/*}${base// /_}"
done' bash {} +
It would descend into hidden dirs, but not rename files there.