Bash – Flattening folder structure

bashrenameshell-script

I have this folder structure:

├── foo1
│   ├── bar1.txt
│   └── bar2.txt
├── foo2
│   ├── bar3.txt
│   └── bar4 with a space.txt
└── foo3
    └── qux1
        ├── bar5.txt
        └── bar6.txt

that I would like to flatten into this, with an underscore between each folder level:

├── foo1_bar1.txt
├── foo1_bar2.txt
├── foo2_bar3.txt
├── foo2_bar4 with a space.txt
├── foo3_qux1.bar6.txt
└── foo3_qux1_bar5.txt

I've looked around and I haven't found any solution that work, mostly I think because my problem has two particularities: there might be more than one folder level inside the root one and also because some files might have spaces.

Any idea how to accomplish this in bash? Thanks!

Edit: Running gleen jackman proposed answer I get this:

enter image description here

There are two underscores for the first level folder. Any idea how to either avoid this or just rename it so that is just one underscore? Thanks.

Best Answer

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 '{}' \; 
Related Question