1

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
Lee
  • 149
  • 2
  • 3
  • 8

1 Answers1

0

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.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501