I have a directory called music who have many albums and separate tracks. Some of them are in subdirectories. What I want is remove this folders and mix all tracks in the music directory without separations.

Will be hard do this manually, so I am looking for some command.


Without find

shopt -s globstar
mv -nv **/*.mp3 /path/to/common/directory
find . -mindepth 1 -type f -exec mv -i "{}" /common/path \;
find . -mindepth 1 -d -type d -exec rmdir "{}" \;

This will move all your music from the current directory to /common/path and the second one will delete all directories. Then you can move all your stuff back to the original directory.

Also, this will prompt you if you want to overwrite files with the same name.

  • Can't I sent the subdirectories files to the music directory directly? – user224753 Feb 26 '18 at 22:57
  • Not with this method. This will throw an error when you try to move the files from the top level of the structure(trying to move the same file on itself). You could however, use -mindepth 2 in the first command and replace /common/path with ., however, this is opening up for another set of issues(llike having a directory with a name of a file you are moving). It's a bit safer to use a different path(empty one) and handle files with the same name. You may as well use cp instead of mv, review and delete the original structure. – man0v Feb 26 '18 at 23:05
find /path/to/music/ -type f -execdir mv -n "{}" /path/to/sharedmusic/ \;

Files with duplicate names will not be moved, but rather left in their original location.

  • If you find yourself with a copy of awesome tune.ogg, would you rather see mv path/to/awesome tune.ogg /path/to/sharedmusic or mv "path/to/awesome tune.ogg" /path/to/sharedmusic? – DopeGhoti Feb 26 '18 at 22:10
  • 1
    is that a reference to the quotes around {}? find doesn't run the command through a shell, so that's not an issue there. (find doesn't even see the quotes, it just sees {} as an argument.) If you had find -exec sh -c 'somecmd "$1"' sh {} \;, then the quotes inside the shell scriptlet would be an issue – ilkkachu Feb 26 '18 at 22:13

You could complete a find for all the files in the sub-directories then have that find command execute move to current directory.

an example of this is found in this answer below. https://stackoverflow.com/questions/22388480/how-to-pipe-the-results-of-find-to-mv-in-linux

Quoted Answer: https://stackoverflow.com/a/22388545/879882

xargs is commonly used for this, and mv has a -t option to facilitate that.

find ./ -name '*article*' | xargs mv -t ../backup

If your find supports -exec ... \+ you could equivalently do

find ./ -name '*article*' -exec mv -t ../backup {}  \+

The -t option is probably a GNU extension. It's of course possible to roll your own, maybe something like

find ./ -name '*article*' -exec sh -c 'mv "$@" "$0"' ../backup {} \+

where we shamelessly abuse the convenient fact that the first argument after sh -c 'commands' ends up as the "script name" parameter in $0 so that we don't even need to shift it.

  • 1
    @Theophrastus we don't know this is for a Linux system with GNU tools. It could be Mac or Solaris. And the point was that mv -t is not POSIX standard – roaima Feb 26 '18 at 22:14
  • I was pointing to an existing answer to a similar question over on stack overflow and only quoted a section of the answer. if you go to the stack overflow question, its has more explanation then what i put here. – thebtm Feb 26 '18 at 22:15
  • 1
    We're not on stackoverflow – roaima Feb 26 '18 at 22:15
  • @roaima I understand this is not Stack Overflow but stack overflow is a stack exchange site like this site, its why I quoted the answer instead of submitting the question as a duplicate question. – thebtm Feb 26 '18 at 22:18