File Management – Flatten Directory and Preserve Names

findrename

How can I flatten a directory in the following format?

Before: ./aaa/bbb/ccc.png

After: ./aaa-bbb-ccc.png

Best Answer

Warning: I typed most of these commands directly in my browser. Caveat lector.

With zsh and zmv:

zmv -o -i -Qn '(**/)(*)(D)' '${1//\//-}$2'

Explanation: The pattern **/* matches all files in subdirectories of the current directory, recursively (it doesn't match files in the current directory, but these don't need to be renamed). The first two pairs of parentheses are groups that can be refered to as $1 and $2 in the replacement text. The final pair of parentheses adds the D glob qualifier so that dot files are not omitted. -o -i means to pass the -i option to mv so that you are prompted if an existing file would be overwritten.


With only POSIX tools:

find . -depth -exec sh -c '
    for source; do
      case $source in ./*/*)
        target="$(printf %sz "${source#./}" | tr / -)";
        mv -i -- "$source" "${target%z}";;
      esac
    done
' _ {} +

Explanation: the case statement omits the current directory and top-level subdirectories of the current directory. target contains the source file name ($0) with the leading ./ stripped and all slashes replaced by dashes, plus a final z. The final z is there in case the filename ends with a newline: otherwise the command substitution would strip it.

If your find doesn't support -exec … + (OpenBSD, I'm looking at you):

find . -depth -exec sh -c '
    case $0 in ./*/*)
      target="$(printf %sz "${0#./}" | tr / -)";
      mv -i -- "$0" "${target%z}";;
    esac
' {} \;

With bash (or ksh93), you don't need to call an external command to replace the slashes by dashes, you can use the ksh93 parameter expansion with string replacement construct ${VAR//STRING/REPLACEMENT}:

find . -depth -exec bash -c '
    for source; do
      case $source in ./*/*)
        source=${source#./}
        target="${source//\//-}";
        mv -i -- "$source" "$target";;
      esac
    done
' _ {} +
Related Question