8

I have 50 folders with some subfolders too, with more than 1000 audio files total. I need to remove all subfolders and put all files in present level. Tried mv */* ./ but it complaints: argument list too long

4 Answers 4

7

I assume that your audio files extention is .mp3

find <AudioFolderPath> -name '*.mp3' -exec mv -it <YourTargetFolder> {} +

Notes:

  • Replace .mp3 with your audio files extention

  • Replace <AudioParentFolderPath> with the parent folder that content your subfolders.

  • Replace <YourTargetFolder> with the folder path that you need to put all files in.

  • If tow files from different subfolders have the same name only one will be moved.

edit : As Costas said : "The -i switch makes mv interactive, it will prompt before overwriting existing files"

4
  • does '-t' allow you to specify the destination first? (as I don't have this option on my "mv" here, I can only assume so as you put first the destination folder and then the list of files to move there... but if not, this will try to fit all in the last filename, giving out a warning) t could be for "target" ? Feb 2, 2015 at 15:01
  • Yes as you said , -t allow to specify the destination first . from the mv manual page : -t, --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY
    – Muhammad Z
    Feb 2, 2015 at 16:55
  • 1
    please note that this is GNU mv's option, and not available on every unices (in some production environment, at least). I provide a more portable solution, but yours works fine for Linux Feb 2, 2015 at 16:57
  • yes @OlivierDulac, you are right,thanks for your note.
    – Muhammad Z
    Feb 2, 2015 at 17:06
5
find . -type f -mindepth 2 -exec mv -t ./ {} +

Note that that command will overwrite any files with the same name. You can use this to be prompted before overwriting:

find . -type f -mindepth 2 -exec mv -it ./ {} +

Explanation

  • -type f : only find regular files.
  • -mindepth 2 : find only files in subdirectories.
  • -exec mv -it ./ {}: the -exec means "run this command on every file found". The {} will be replaced with the file names. The -i switch makes mv interactive, it will prompt before overwriting existing files and the -t sets the target directory to ./.
  • + : put files together (in one argument line) so many as shell can operate with command to invoke command minimum times (not one by one but one to several).

Regarding futher empty folder deletions you can use same recepie:

find . -type d -empty -delete
5
  • 1
    -type f selects only plain files, excluding symbolic links, named pipes and the like. To move all files other than directories you can do ! -type d.
    – jimmij
    Feb 2, 2015 at 11:59
  • @jimmij I suppose nobody store audio-files as named pipe or something else. If you worry about symlinks you can use -L parameter
    – Costas
    Feb 2, 2015 at 12:04
  • 1
    -i is standard, -t is GNU-only (nothing to do with Linux which is just a kernel found in some GNU and non-GNU systems) Feb 2, 2015 at 12:08
  • I concur with @StéphaneChazelas : -t doesn't exist on some systems (like a not-so-ancient AIX) Feb 2, 2015 at 15:02
  • @OlivierDulac It is almost impossible to find decision to satisfy everybody so the different variants are welcome. Nobody prohibit you to change string to find . -type f -mindepth 2 -exec mv {} ./ \;
    – Costas
    Feb 2, 2015 at 16:02
2

Yes, that's a limit on the cumulative size of arguments and environment passed to the execve() system call when executing an external command.

With zsh, you can use its builtin mv instead:

zmodload -F zsh/files +b:zf_mv
zf_mv ./*/* .

Or use zargs to break the list into manageable chunks:

autoload zargs
zargs -Ifiles ./*/* -- mv files .

With ksh93:

command -x mv ./*/* .

With GNU xargs and with GNU mv with a shell where printf is builtin (most, mksh being the notable exception):

printf '%s\0' ./*/* | xargs -r0 mv -t .
1
  • Please keep in mind that OP want to move only files, not directories, so you need to take care of that. In zsh case you can put some glob qualifiers, e.g. (.) or (^/) after last *.
    – jimmij
    Feb 2, 2015 at 12:29
0

A quite portable solution could be :

find all files in every subfolders, and move them in the current dir

find ./*/ -type f -print | xargs mv -i "{}" ./

You can add a | egrep "\.au$|\.mp3$|\.ac3$" in between to also ensure the files you found are files with an audio extension (add as many extension as necessary to cover all type, I just provide 3 common ones)

3
  • In your case there is no need to call find at all. Just enough echo or printf
    – Costas
    Feb 2, 2015 at 16:04
  • @Costas: the OP mention there are so many files that "*" can't be expanded ... Here I just expand the 50 folders names, and the rest is handled by xargs Feb 2, 2015 at 16:05
  • But find do not settle the problem but xargs do.
    – Costas
    Feb 2, 2015 at 16:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .