Flattening folder structure

find */ -type f -exec bash -c 'file=${1#./}; echo mv "$file" "${file//\//_}"' _ '{}' \;

remove echo if you're satisfied it's working. Don't worry that the echo'ed commands don't show quotes, the script will handle files with spaces properly.

If you want to remove the now empty subdirectories:

find */ -depth -type d -exec echo rmdir '{}' \; 

Using perl's rename :

find . -depth -type f -exec rename 's@(?<!\.)/@_@g' -- {} \;

OUTPUT

$ find -type f
./foo2_bar4 whit a space.txt
./foo3_qux1_bar6.txt
./foo2_bar3.txt
./foo3_qux1_bar5.txt
./foo1_bar2.txt
./foo1_bar1.txt

NOTE

  • I use a negative look behind (?<!\.) to don't touch the first ./
  • I keep the empty dirs, feel free to :

    find . -depth -type d -exec rm {} \;

warning There are other tools with the same name which may or may not be able to do this, so be careful.

If you run the following command (GNU)

$ file "$(readlink -f "$(type -p rename)")"

and you have a result like

.../rename: Perl script, ASCII text executable

and not containing:

ELF

then this seems to be the right tool =)

If not, to make it the default (usually already the case) on Debian and derivative like Ubuntu :

$ sudo update-alternatives --set rename /path/to/rename

(replace /path/to/rename to the path of your perl's rename command.


If you don't have this command, search your package manager to install it or do it manually


Last but not least, this tool was originally written by Larry Wall, the Perl's dad.