4

My files have the following structure:

11
--11a
-----a.jpg
-----b.jpg
-----....
--11b
-----d.jpg
-----g.jpg
...

I want to have all the .jpg files in one folder:

11
-a.jpg
-b.jpg
-d.jpg
-g.jpg
...

Basically I have subfolders with many .jpg files and I want to move all of them to one directory (e.g. parent).

I have tried: mv */*.jpg all but I get -bash: /bin/mv: Argument list too long.

Some posts suggest xargs and some other the find solution but unfortunately nothing seems to be working for me.

  • Are you certain all the file names are unique? How should conflicts be handled if not? I think `find` will give you a solution, but you need to answer these questions before I can suggest a solution. – AFH Oct 06 '16 at 23:09
  • Yes the file names are unique so there are no conflicts at all. – Menelaos Kotsollaris Oct 06 '16 at 23:45
  • [This](http://superuser.com/a/496768/468052) might work for osx as well. It is an elegant gui solution. – NonlinearFruit Oct 07 '16 at 16:07

2 Answers2

5

If the file names are unique, use:

find {base folder}/11 -name "*.jpg" -exec mv {} {base folder}/11/ \;

where {base folder} is where the directory 11 resides.

This runs the mv command on each file in turn: it will be a lot slower than moving all the files in a single mv command, but there will be no restrictions on the length of the argument list.

If some of the file names could be in upper case, you can use -iname instead of -name. You can also add -n to make sure you do not overwrite a file which has been moved already (you need to check that your mv has this option - if not use -i, though this will prompt on conflicts).

You can get rid of any empty directories with:

rmdir {base folder}/11/*

You will need to investigate any directories that remain after this command.

AFH
  • 17,300
  • 3
  • 32
  • 48
  • How about `find … -exec mv … +`? It should pass multiple paths to `mv`, taking care of the line length though. – Kamil Maciorowski Oct 07 '16 at 16:09
  • @KamilMaciorowski - I'm sceptical: the line length will probably work out the same as in your original `mv` command, and subject to the same limitations. – AFH Oct 07 '16 at 22:34
  • Eh, even worse: it won't work at all. Now i see [here](http://unix.stackexchange.com/a/152723/108618) that `only a that immediately follows an argument containing only the two characters "{}" shall punctuate the end of the primary expression.` Still `find {base folder}/11 -name "*.jpg" -exec mv -t {base folder}/11/ {} +` should work (it appears this is exactly the purpose of `-t` option). The downside is the `find` will match already moved files. One can fight it specifying depth, or accept `source and target are the same file` error that should do no harm. – Kamil Maciorowski Oct 08 '16 at 04:51
  • There is an ordering option on `find` which allows subdirectories to be traversed in such a way that finding the same file in two places should not occur. Another approach is to process the files a directory at a time, instead of a file at a time: this should limit the `mv` parameter length. Use something like `for d in {base folder}/11/; do [ -d "$d" ] && eval mv "$d/*.jpg" {base folder}/11/; done`. This needs to be elaborated, as in this simple form it will generate errors, but it shows the approach. I've just had a gruelling 24 hours, so I can't work out all the niceties at present. – AFH Oct 08 '16 at 23:13
  • Works for me, other solutions online did not, thanks! – 00-BBB Mar 15 '21 at 16:26
-2

This should be as easy as "mv /.your_extension ./"