How to move all files from current directory to upper directory?

How to move all files from current directory to upper directory in linux?

I tried something like mv *.*, but it doesn't work.


Solution 1:

The command you are looking for is

mv * .[^.]* ..

or (see below for more info):

(shopt -s dotglob; mv -- * ..)

Explanation: the mv command moves files and directories. The last argument to mv is the target (in this case the directory one step "up" in the tree, ..). The arguments before that are the source files and directories. The asterisk (*) is a wildcard which matches all files which do not start with a dot. Files that start with a dot (dotfiles) are "hidden". They are matched using the pattern .[^.]* (see edit below).

See the manpage which I linked for more information on mv.


Why .[^.]* instead of .* ?

As Chris Johnsen correctly points out: the pattern .* also matches . and ... Since you don't want to (and cannot) move those, it's better to use a pattern which matches any filename starting with a dot except those two. The pattern .[^.]* does just that: it matches any filename (1) starting with a dot (2) followed by a character which is not a dot (3) followed by zero or more arbitrary characters.

As Paggas points out, we'd also have to add the pattern .??* in order to match files starting with two dots. See his answer for an alternative solution using find.

Arjan's answer mentions shopt in order to avoid all those issues with dotfiles. But then there is still the problem with files starting with a dash. And it requires three commands. Still, I like the idea. I propose to use it like this:

(shopt -s dotglob; mv -- * ..)

This executes shopt in a subshell (thus no second call to shopt required) and uses -- so that files starting with a dash will not be interpreted as arguments to mv.

Solution 2:

Short answer: use

find . -mindepth 1 -maxdepth 1 -exec mv -t.. -- {} +

Long answer:

The command

mv * .* ..

will not work since .* can match . and ... But the command

mv * .[^.]* ..

will also not work, since .[^.]* won't match, e.g., ..filename! Instead, what I do is

mv * .[^.] .??* ..

which will match everything except . and ... * will match everything that doesn't start with a ., .[^.] will match all 2 character filenames starting with a dot except .., and .??* will match all filenames starting with a dot with at least 3 characters.

Better yet, you can use

find . -mindepth 1 -maxdepth 1 -exec mv -t.. -- {} +

which avoids the ugly glob hacks in mv * .[^.] .??* ..!

Solution 3:

Just for the sake of completeness, one can also tell the Bash shell to include hidden files, using shopt:

shopt -s dotglob
mv -- * ..
shopt -u dotglob

Solution 4:

The mv lacks the functionality of moving hidden files when using * - so why not use copy instead?

cp -rf . ..

rm -rf *

No need to get into complex solutions of dotglobbing and using find commands.

Solution 5:

rsync -a --remove-source-files . ..

rsync is an extremely powerful file copying tool, generally used for performing efficient incremental remote backups and mirrors.

With the above command, we are telling rsync to copy the content of . into ..

The switch -a enables recursion into . subdirectories and enables some other common options.

The switch --remove-source-files tells rsync to remove the source files after a successful copy, i.e. it makes rsync behave similarly to the mv command.