[Question]
  [
It is simple. I cannot stand when people use spaces when naming files. It sometimes wrecks console commands and makes the output of ls ugly.
The challenge is to write a program (only ascii characters) which
1. renames all files (including directories) in the current directory to versions with spaces removed or replaced by '\_'
2. on collision, you need to append a unique identifier (up to you)
3. descends recursively into all subdirectories
You can assume UNIX-style path names. Who would need this program on a Windows machine anyways?
This is code golf, the shortest program wins (#ascii characters). Since I hate spaces so much, each space has to be counted twice.
Please provide your language, score, program and a short description of how to run it.
The program must compile and execute with reasonable effort on my linux machine.
EDIT: As Etan requested a file structure for testing, here is the script I currently use to create a suitable file tree:
```
#!/bin/bash
rm -r TestDir
touchfiles()
{
    touch my_file
    touch my__file
    touch "my file"
    touch "my  file"
    touch " my_file  "
}
mkdir TestDir
cd TestDir
touchfiles
for dir in "Test Sub" Test_Sub "Te stSub" Te_stSub
do
    mkdir "$dir"
    cd "$dir"
    touchfiles
    cd ..
done
```
  
[Answer]
## Bash 116 bytes, 16 spaces
```
find . -depth -exec bash -c 'B=${0##*/}
M="${0%/*}/${B// /_}"
while [ -e "$M" ]
do M=$M.
done
mv "$0" "$M"' {} \;
```
I didn't suppress errors to gain a couple more bytes. This will not have any collisions.
If non-posix GNU `find` can be expected, this can be shortened further:
## Bash 110 bytes, 15 spaces
```
find -d -exec bash -c 'B=${0##*/}
M="${0%/*}/${B// /_}"
while [ -e "$M" ]
do M=$M.
done
mv "$0" "$M"' {} \;
```
Removing spaces instead of replacing them uses two less bytes:
## Bash 108 bytes, 15 spaces
```
find -d -exec bash -c 'B=${0##*/}
M="${0%/*}/${B// }"
while [ -e "$M" ]
do M=$M.
done
mv "$0" "$M"' {} \;
```
Note: if tabs can be used instead of spaces, only 1 space is needed (the one in the match rule for substitution at line 2).
Thanks to Dennis for finding bug on double quote (and providing solution)
[Answer]
## Zsh + GNU coreutils — 48 bytes (1 space)
```
for x   (**/*(Dod))mv   -T  --b=t   $x  $x:h/${${x:t}// }
```
It's weird that you hate (ASCII) spaces but are fine with tabs and newlines, but I guess it takes all kinds. 
[zmv](http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#index-zmv) solves [a lot of file renaming problems](https://unix.stackexchange.com/search?q=zmv) concisely (and only slightly obscurely). However, it insists on the targets being unique; while you can easily add unique suffixes, adding a suffix only if it would be needed pretty much requires re-doing all the work. So instead I loop manually and rely on [GNU mv](http://www.gnu.org/software/coreutils/manual/coreutils.html#mv-invocation) to append a unique identifier in case of collision (`--backup` option, plus `--no-target-directory` in case a target is an existing directory, as otherwise `mv` would move the source inside that directory).
`(od)` is a [glob qualifier](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers) to sort the output with directories appearing after their content (like find's `-depth`). `D` includes dot files in the glob. `:h` and `:t` are [history modifiers](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Modifiers) similar to `dirname` and `basename`.
`mv` complains that it's called to rename files to themselves, because the glob includes file names without spaces. C'est la vie.
Ungolfed version:
```
for x in **/*\ *(Dod); do
  mv --no-target-directory --backup=numbered $x ${x:h}/${${x:t}// /}
done
```
[Answer]
# Python 180 bytes
```
from    os  import*
t,c,h='.',chdir,path
def g(p):
    c(p)
    for x   in  listdir(t):
        if h.isdir(x):g(x)
        n=x.replace(' ','')
        while h.exists(n):n+=t
        if' 'in x:rename(x,n)
    c(t*2)
g(t)
```
only 2 spaces if you use tab for indentation :-)
[Answer]
If the order of collided file suffixes does not need to give precedent to the pre-existing file then the following works for me:
## bash/find/mv 84 bytes, 16 spaces
```
find -depth -execdir bash -c '[ "${0//[^ ]}" ] && mv -{T,--b=t} "$0" "${0// }"' {} \;
```
## bash/find/mv 82 bytes, 14 spaces
```
find -depth -execdir bash -c '[ "${0//[^ ]}" ]&&mv -{T,-b=t} "$0" "${0// }"' {} \;
```
Cuddled `&&` to save two space bytes.
## bash/find/mv 60 bytes, 11 spaces
```
find -d -execdir bash -c 'mv -{T,-b=t} "$0" "${0// }"' {} \;
```
Drops error protection so it gets errors from mv on files which have no spaces to start with.
Edit: Dropped the quotes from `{}` as reminded by Dennis. Also allowed `find` to scream about portability and deprecation in the shortest version where `mv` is already screaming about moving a file on top of itself.
Edit 2: Added `-T` to `mv` command to avoid nesting directories instead of renaming as pointed out by pqnet. Used brace expansion at cost of one character over just using one space.
[Answer]
## NodeJS – 209 bytes, 3 Whitespaces
```
s=require('fs');function a(d){s.readdirSync(d).forEach(function(f){f=d+'/'+f;i=0;r=f;if(/ /.test(f)){r=f.replace(' ','');while(s.existsSync(r))r+=i++;s.renameSync(f,r)}s.statSync(r).isDirectory()&&a(r)})}a('.');
```
[Answer]
## POSIX `sh` + GNU `find` + GNU `mv` 67 ASCII bytes + one *(literal)* space
```
find    -d  -exec   sh  -cf 'IFS=\ ;IFS=_   set $0;mv   --b=t   "$0"    "$*"'   {}  \;
```
I don't know if it fits, but with this any *sequence* of spaces is elided to a single `_` - I like it anyway. Actually any *sequence* but leading/trailing spaces that is - those are automatically truncated *(which is also, I think, a beneficial behavior)*. Thanks to Gilles for pointing this out.
This just uses the internal field separator to separate fields.
It's fairly... *chatty*...
...oh man. I knew the tab thing was cheap, but I thought it was at least clever. Now I'm just late to the party...
[Answer]
# Bash - 86 bytes
```
find    .   -d|while    IFS=""  read    f;do    t=${f##*/};mv   --b=t   -T  "$f"    "${f%/*}"/${t// /};done
```
[Answer]
## Bash + Perl `rename` 64
(`rename` is the Perl script on Debian and derivatives, not the util-linux command.)
```
find . -depth -name "* *" -execdir rename 'y/ /_/' * \;
```
[Answer]
# PHP, ~~147~~ 145 bytes, ~~2~~ 1 space~~s~~ -> 146
```
function    s(){foreach(glob("*")as$n){is_dir($n)&&chdir($n)&s()|chdir("..");if($n<$r=strtr($n," ",_)){while(file_exists($r))$r.=_;rename($n,$r);}}}
```
recursive function. Run with `s(".");`
Loop through `glob` results for given path:
* if directory, recurse
* replace spaces with underscore
* if strings differ
	+ while new filename is taken, append underscore
	+ rename file/directory
[Answer]
# Python, 187
165, plus 22 penalty points for the spaces.
```
from os import*
u='_';j=path.join
for t,d,f in walk('.',0):
 for z in f+d:
  n=z.replace(' ',u)
  if n!=z:
   while path.exists(j(t,n)):n+=u
   rename(j(t,z),j(t,n))
```
# 166, using [Emanuele's](https://codegolf.stackexchange.com/a/35853/14947) \t trick:
Only a single space in this one!
```
from    os  import*
u='_';j=path.join
for t,d,f   in  walk('.',0):
    for z   in  f+d:
        n=z.replace(' ',u)
        if  n!=z:
            while   path.exists(j(t,n)):n+=u
            rename(j(t,z),j(t,n))
```
[Answer]
# LiveScript - 166
(Replace spaces with tabs.)
```
(a=->(s=require \fs)readdirSync(it)map (f)->f=it+'/'+f;r=f.replace /\s/g,i='';(while f!=r&&s.existsSync r=>r+=i++);s.statSync(f)isDirectory(s.renameSync f,r)&&a r) \.
```
Based on [nderscore's](https://codegolf.stackexchange.com/users/20160/nderscore) [optimized version](http://pastie.org/9456328) of [c.P.u1](https://codegolf.stackexchange.com/users/21777/c-p-u1)'s [answer](https://codegolf.stackexchange.com/a/35870/344).
[Answer]
**POSIX(Tested on zsh) + basic Linux commands 151**
```
export IFS='
'
for f in $(ls -R1);do export n=$(echo $f|tr ' ' '_');yes n|mv $f $n || yes n|mv $f `echo $n;echo $f|md5sum`
done
```
[Answer]
## Ruby 194
```
require'find'
require'fileutils'
Find.find(?.).sort{|a,b| b.length<=>a.length}.each {|f|
if f.match(/ /)
o=f.tr(' ',?_)
begin
raise if File.exist? o
FileUtils.mv f,o
rescue
o+=?_
retry
end
end}
```
[Answer]
**Bash 4+ 111 bytes**
```
shopt -s dotglob globstar
for f in **
do
n=${f// /}
while [[ $f != $n && -e $n ]]
do n+=1
done
mv "$f" $n
done
```
[Answer]
**Groovy, 139 characters**
```
def c
c={
f->
def g=new File(f.parent,f.name.replaceAll('\\s',''))
f.renameTo(g)
!g.directory ?: g.eachFile(c)
}
new File('.').eachFile(c)
```
according to @edc65 comment
**Groovy, handle collisions, 259 characters**
```
def c
c={
p,l,f->
def g=new File(p,f.name.replaceAll('\\s',''))
f==g?:
(g.exists()?f.renameTo(g.toString()+l.indexOf(f.name)):f.renameTo(g))
!g.directory?:g.eachFile(c.curry(g,g.list().toList()))
}
def r=new File('.')
r.eachFile(c.curry(r,r.list().toList()))
```
]