15

I have a directory with lots of files and directories in it. In order to tidy it up, I'm going to put all those files into a directory, so I was going to do something like this:

$ ls | wc -l
123
$ mkdir new_directory
$ mv * ./new_directory

However that obviously won't work because then it'll try to move new_directory into new_directory. Is there some simple way to do what I want in one line without me having to copy and paste all the files and directories in that directory?

1
  • 3
    it works, it just prints an error message that it's unable to move new_directory into itself.
    – cas
    Sep 8 '09 at 21:49
19

Your

mv * ./new_directory
command will actually work; it'll just print a warning that it can't move that directory into itself.

2
  • The 'only' problem with this is that if the total expansion of the command becomes too long (i.e. too many files, too long names) this will no longer work. Sep 8 '09 at 11:22
  • As a side note, if you're going to do this with a git mv you must use the -k flag, since git will fail by default, not just spit out a warning. So you'll need to do git mv -k * ./new_dir.
    – Yuval A
    Apr 11 '12 at 22:36
11

A fast and dirty oneliner.

mv `ls -A | grep -v new_directory` ./new_directory
4
  • 1
    Will not work: a plain ls will not show dotfiles.
    – wzzrd
    Sep 8 '09 at 9:51
  • Very good point. Fixed that with an -a.
    – Rembane
    Sep 8 '09 at 9:54
  • 2
    So instead of trying to mv new_directory to itself (Original question) you are now trying to move . and .. into new_directory. Sep 8 '09 at 11:21
  • 2
    Thanks for the feedback Niels. Fixed it with an upper a which removes the . and the .. from the directory listing.
    – Rembane
    Sep 8 '09 at 11:30
8

If you're just looking for the files (i.e. not directories), then

find . -type f -maxdepth 1 -exec mv {} ./new_directory/ \;

is the most portable solution. For speed, you should move find and xargs, with -print0 and -0, but only if you've got GNU find and xargs.

7
  • 3
    Using a fairly recent GNU find, you could also use \+ instead of \; to decrease the number of mv's we are making.
    – wzzrd
    Sep 8 '09 at 9:50
  • If you've got GNU find, you're as well to use xargs, which'll do the same, and let you run multiple mvs at the same time with the -p flag.
    – Cian
    Sep 8 '09 at 9:59
  • cool use of find - though I've definitely been on systems that don't have one, sadly :(
    – warren
    Sep 8 '09 at 10:10
  • Really? find is (afaik) specified in SUS, so everything should have it. The only issue is whether it's GNU find (which has lots of nice cool options) or regular find.
    – Cian
    Sep 8 '09 at 10:27
  • Yep, it appears to be opengroup.org/onlinepubs/009695399/utilities/find.html
    – Cian
    Sep 8 '09 at 10:29
6

The times that I've had this problem, I've done one of the following:

$ mkdir ../new-directory
$ mv * ../new-directory/
$ mv ../new-directory .

or

$ mkdir .new-directory
$ mv * .new-directory/
$ mv .new-directory new-directory

The second form takes advantage of the wildcard skipping filenames that start with '.'

1
  • I forgot the wild-card skipped dotted files; thanks for the reminder ! :)
    – aemonge
    Aug 15 '17 at 12:33
2

what about:

cd ..
mv old_dir new_directory
mkdir old_dir
mv new_directory old_dir

IOW, don't move the contents into a new directory, but put this directory inside a new one.

1

In similar fashion to @Rembrane's answer (though not a one-liner):

for FN in *
do
    if [ "<new_dir>" != $FN ] then
        mv $FN <new_dir>
done

This should be 100% portable - even if find is sadly absent from your system.

2
  • find is required in the single unix spec. As such, it should never be absent (not that you couldn't build something with out it. But I'd imagine it'd require a horrendous amount of effort, and no vendor system will lack it)
    – Cian
    Sep 8 '09 at 10:30
  • maybe it's some hyper-paranoid sysadmin yoinking findutils or its equivalent? not sure, but I know I've run into boxen that don't have it :(
    – warren
    Sep 8 '09 at 16:15
1

My suggestions: As stated by others the

mv * ./new_directory

will work find IFF the total expansion is short enough.

Other wise you can try this one that scales to much much larger numbers of files:

find . -type f -maxdepth 1 | xargs -s100000 echo | xargs -iXXX mv XXX new_directory

Explanation

  1. List all files.
  2. Group all filesnames into chunks of max 100000 chars.
  3. Construct a single mv command per chunk.
4
  • breaks if you've got any spaces in your file names
    – Cian
    Sep 8 '09 at 11:54
  • You're right. So i guess this should be augmented with -print0 and -0 flags to fix. Sep 8 '09 at 12:11
  • I've tried with -print0 and -0 and it still breaks. Sep 8 '09 at 19:14
  • find: warning: you have specified the -maxdepth option after a non-option argument -type, but options are not positional (-maxdepth affects tests specified before it as well as those specified after it). Please specify options before other arguments. Sep 8 '09 at 19:14
1

Use:

find -mindepth 1 -maxdepth 1 \! -name new_directory -print0 | \
    xargs -0 -P 100 -I'{}' mv '{}' new_directory

From the xargs man page:

-P max-procs

  Run up to max-procs processes at a time;
-1

To avoid the error message and keep it simple:

mv *.* ./new_Folder

will do the same thing but avoid the error message (unless you have dots in your folder names I guess).

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.