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

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"

  • 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" ? – Olivier Dulac Feb 2 '15 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 Feb 2 '15 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 – Olivier Dulac Feb 2 '15 at 16:57
  • yes @OlivierDulac, you are right,thanks for your note. – Muhammad Feb 2 '15 at 17:06
4
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
  • 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 '15 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 '15 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) – Stéphane Chazelas Feb 2 '15 at 12:08
  • I concur with @StéphaneChazelas : -t doesn't exist on some systems (like a not-so-ancient AIX) – Olivier Dulac Feb 2 '15 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 '15 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 .
  • 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 '15 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)

  • In your case there is no need to call find at all. Just enough echo or printf – Costas Feb 2 '15 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 – Olivier Dulac Feb 2 '15 at 16:05
  • But find do not settle the problem but xargs do. – Costas Feb 2 '15 at 16:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.