119

I am at the path:

/myuser/downloads/

And I create a sub folder:

/myuser/downloads/new

Now I want to move all files and folders/sub-folders in the downloads folder to the sub-folder.

how can I do this?

I tried:

mv -R *.* new/

But move doesn't take the -R switch it seems.

Blankman
  • 8,605

8 Answers8

170

The command

mv !(new) new

should do the trick. If it doesn't work, run shopt -s extglob first.

To also move hidden files/directories (that beginning with a dot), run also shopt -s dotglob first.
So, to sum up:

shopt -s extglob dotglob
mv !(new) new
shopt -u dotglob

(It is always better to unset dotglob to avoid bad surprises with shopt -u dotglob)

Adil
  • 3
enzotib
  • 96,093
26

I found something like this but is a bit simpler to understand, and it might work well for you too:

ls | grep -v new | xargs mv -t new

Adding an explanation to the above solution:

From man pages:

  • mv -t

    -t, --target-directory=DIRECTORY
          move all SOURCE arguments into DIRECTORY
    
  • grep -v

    -v, --invert-match
          Invert the sense of matching, to select non-matching lines.
    

Explained by step:

  • ls will list the files in current directory
  • grep -v new will return piped to that is not match new
  • xargs mv -t new will move the files piped to it from grep -v to the target directory
lockwobr
  • 505
25

Just use mv * subdir1 and ignore the warning.

You can just use mv * subdir1. You will see a warning message relating to trying to move subdir1 into itself, like this:

mv: cannot move 'subdir1' to a subdirectory of itself, 'subdir1/subdir1'

But it will move all of the other files and directories to subdir1 correctly.

An example:

$ ls
$ mkdir dir1 dir2 dir3      
$ touch file1.txt file2.txt file3.txt
$ mkdir subdir1
$ ls
#=> dir1  dir2  dir3  file1.txt  file2.txt  file3.txt  subdir1
$ mv * subdir1
#=> mv: cannot move 'subdir1' to a subdirectory of itself, 'subdir1/subdir1'
$ ls
#=> subdir1
$ ls subdir1
#=> dir1  dir2  dir3  file1.txt  file2.txt  file3.txt
11

Simple idea. Assuming you are in /myuser, rename downloads to new, create a new downloads directory then move new into it.

mv downloads new # downloads is now called new
mkdir downloads # create new directory downloads
mv new downloads # move new into it.
jpezz
  • 1,140
1

You can try this alternative process –– remain in the path

/myuser/downloads/

but, instead of first creating the /myuser/downloads/new/ directory, instead create a folder in the /myuser/ directory, with the command mkdir ../new, then move all the files in downloads to new, and finally move new into downloads. You can do this in one line, while in the /myuser/downloads/ path, with the command:

mkdir ../new && mv * ../new && mv ../new ../downloads

In this case, you don't have to worry about any sort of "filtering" of files/folders, since new is on the same level of the path as downloads, so you can just move everything in downloads to new, and then move new into downloads`.

However, if you already have the subfolder new created and don't want to create another one, not to worry –– just change the mkdir command on the left-hand side of the first && in the command shown above to an mv command, pushing new up in the path; in other words, while you're still in /myuser/downloads/, you can change mkdir ../new to mv new ... Then the subfolder new [in the path /myuser/downloads/new/] gets pushed up to /myuser/new/, at the same level as /myuser/downloads/, and then you can run the rest of the command as it is shown above. All together, we have, starting from the path /myuser/downloads/:

mv new .. && mv * ../new && mv ../new ../downloads

and, since you wanted to "move all files and folders/sub-folders in the downloads folder to the sub-folder [new]", you're done! If you had wanted to move only files (or only folders or [insert more granular object movement]), then you'd have to use other commands that can "filter" objects, such as grep. The commands written above are sufficient for your purposes, though.

adamcatto
  • 111
  • 2
1

If you want to move all the files from a folder to one of its subfolders you can use the following command:

find /myuser/downloads/ -type d -name 'new' -prune -type f | xargs mv -t /myuser/downloads/new

It will find all the files and then move them to your subfolder.

@waltinator: added -type d -name 'new' -prune to prevent traversal of /myuser/downloads/new.

waltinator
  • 37,856
demian
  • 11
  • 1
0

As some of the answers say, you can use mv * subfolder/ and ignore the warning. This solution is simple and good without unnecessary complexity!

However, there may be cases where this can cause scripts to fail because the exit code of mv is 1 in this case. In such scenarios you can do the following to keep the scripts happy.

mv * subfolder/ || true

and to also suppress the warning,

mv * subfolder/ 2> /dev/null || true

The above was useful for my work when I used git filter-branch and supplied it with mv * subfolder/. It did not run successfully and then the above solution worked. (Side note: filter-branch can be error prone, so use filter-repo instead)

codeman48
  • 109
-1

Move all files in a directory into a subdirectory

ls -A | grep -v <your-sub-dir> | xargs -I {} mv {} <your-sub-dir>

Example

# setup example directory structure
mkdir -p parent-dir && cd parent-dir && touch file1 file2 && mkdir -p sub-dir
# parent-dir/
# ├── file1
# ├── file2
# └── sub-dir/

move all files to the subdirectory while in the parent directory

ls -A | grep -v sub-dir | xargs -I {} mv {} sub-dir

parent-dir/

└── sub-dir/

├── file1

└── file2

Explaination

ls -A: returns all files including .hidden-files, but excludes . and ..

grep -v sub-dir: skip sub-dir, i.e. don't try mv sub-dir sub-dir as you can't move a dir into itself

xargs -I {} mv {} sub-dir: For each file, move it to the sub-dir. It does this by substituting {} with the filename.

$ echo file | xargs -I {} echo mv {} sub-dir 
mv file sub-dir

The -I {} just sets up the substitution symbol, can use anything, i.e. %

$ echo file | xargs -I % echo mv % sub-dir mv file sub-dir

Debugging

Use echo to debug; I started with the following command to figure it out as it will print out the commands that will be executed.

ls -a | xargs -I {} echo mv {} sub-dir 
mv . sub-dir
mv .. sub-dir
mv file1 sub-dir
mv file2 sub-dir
mv sub-dir sub-dir

mv . sub-dir, mv .. sub-dir and mv sub-dir sub-dir would all fail.