With POSIX tools,
find . -type f -exec sh -c 'for f; do dirn="${f%/*}"; mv -- "$f" "$dirn${f##*/}"; done' sh {} +
find
invokes a shell and executes the for loop for each file.
dirn="${f%/*}"
gets the parent directory name by excluding all that is after (and including) the last slash in the file name.
${f##*/}
gets the filename without the path by excluding all that is before (and including) the last slash in the file name.
Those two shell constructs do the same as dirname
and basename
, so an equivalent form of the command is
find . -type f -exec sh -c 'for f; do mv -- "$f" "$(dirname "$f")$(basename "$f")"; done' sh {} +
, although this one should be slower as it needs to spawn two extra processes for each file.
If you do not need to descend into more than a single directory, such as your example shows, a simple shell loop does it:
for f in */*; do dirn="${f%/*}"; echo mv -- "$f" "$dirn${f##*/}"; done
sh {} +
at the end – benaiu Aug 13 '20 at 03:19