A
for loop simply breaks the input (the part after "in", or the positional parameters) up into separate "words" and processes them individually. If you want to take "per line" input from an external command or file then you should use a
while+read loop instead.
Also, while the above suggestion works in this situation, using a pipe to feed the loop is not the best option because the loop will run in a subshell and any variables set inside it will be lost when the loop terminates. This is the recommended way:
Code:
while read _source; do
mv "${_source}" "${_source// /_}"
done < <(find ./)
See here:
http://mywiki.wooledge.org/BashFAQ/024
(Edit: That find command will also include directories in the input, so you may have problems if you're trying to do this recursively, as it will rename the directory before the files inside it, and so subsequent
mv commands will fail. You should use the
-type f option to limit it to files only, then run it again with
-type d to process the directories ).
Incidentally, if all you want to do is grab files from the current directory, then you don't need find at all, just
globbing, and you can go back to using a for loop (globbing expansion takes place after word breaking, so filenames won't be broken up).
Code:
for source in ./* ; do
mv "${_source}" "${_source// /_}"
done
Finally, instead of writing your own scripts, you might consider using one of the many useful bulk renaming programs that are already out there. I like qmv from
renameutils, for example, and the
perl-based rename utility that comes with some distros. So I just do this to remove spaces from filenames:
Code:
rename -v 's/ /_/g' ./*
Use your google-fu for more.
http://www.google.com/search?&q=linux+bulk+rename