Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

How do I move all files in a directory (including the hidden ones) to another directory?

For example, if I have a folder "Foo" with the files ".hidden" and "notHidden" inside, how do I move both files to a directory named "Bar"? The following does not work, as the ".hidden" file stays in "Foo".

mv Foo/* Bar/

Try it yourself.

mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
share|improve this question

migrated from stackoverflow.com Jan 24 '11 at 19:33

This question came from our site for professional and enthusiast programmers.

    
    
Bah, I knew I should have refreshed the answers before typing mine up. Very helpful link. – Steven D Jan 24 '11 at 19:48
    
Sadly, this question ended up here because I said on SO that it should move here or SU, so of course it moved here when there was a duplicate on SU already :) – Michael Mrozek Jan 24 '11 at 20:06
    
Personally, I think *nix specific questions and answers should be off-topic on SU. With the current rules we end up with tons of content collisions between the two - like this question. – Cory Klein May 12 '14 at 17:27
up vote 92 down vote accepted

Zsh

mv Foo/*(DN) Bar/

or

setopt -s glob_dots
mv Foo/*(N) Bar/

(Leave out the (N) if you know the directory is not empty.)

Bash

shopt -s dotglob nullglob
mv Foo/* Bar/

Ksh93

If you know the directory is not empty:

FIGNORE='.?(.)'
mv Foo/* Bar/

Standard (POSIX) sh

for x in Foo/* Foo/.[!.]* Foo/..?*; do
  if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done

If you're willing to let the mv command return an error status even though it succeeded, it's a lot simpler:

mv Foo/* Foo/.[!.]* Foo/..?* Bar/

GNU find and GNU mv

find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +

Standard find

If you don't mind changing to the source directory:

cd Foo/ &&
find . -name . -o -exec sh -c 'mv -- "$@" "$0"' ../Bar/ {} + -type d -prune

Here's more detail about controlling whether dot files are matched in bash, ksh93 and zsh.

Bash

Set the dotglob option.

$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero

There's also the more flexible GLOBIGNORE variable, which you can set to a colon-separated list of wildcard patterns to ignore. If unset (the default setting), the shell behaves as if the value was empty if dotglob is set, and as if the value was .* if the option is unset. See Filename Expansion in the manual. The pervasive directories . and .. are always omitted, unless the . is matched explicitly by the pattern.

$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one

Ksh93

Set the FIGNORE variable. If unset (the default setting), the shell behaves as if the value was .*. To ignore . and .., they must be matched explicitly (the manual in ksh 93s+ 2008-01-31 states that . and .. are always ignored, but this does not correctly describe the actual behavior).

$ echo *
none zero
$ FIGNORE='@(.|..)'
$ echo *
..two .one none zero
$ FIGNORE='n*'
$ echo *
. .. ..two .one zero

You can include dot files in a pattern by matching them explicitly.

$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero

To have the expansion come out empty if the directory is empty, use the N pattern matching option: ~(N)@(*|.[^.]*|..?*) or ~(N:*|.[^.]*|..?*).

Zsh

Set the dot_glob option.

% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero

. and .. are never matched, even if the pattern matches the leading . explicitly.

% echo .*
..two .one

You can include dot files in a specific pattern with the D glob qualifier.

% echo *(D)
..two .one none zero

Add the N glob qualifier to make the expansion come out empty in an empty directory: *(DN).


Note: you may get filename expansion results in different orders (e.g., none followed by .one followed by ..two) based on your settings of the LC_COLLATE, LC_ALL, and LANG variables.

share|improve this answer
    
Why nullglob? It would make more sense to abort the mv command (like fish, csh/tcsh, zsh (without (N)) do, or bash with failglob) than running a mv /Bar/ command which makes little sense. – Stéphane Chazelas Feb 21 at 16:29
    
I'd say your GLOBIGNORE description is inaccurate and misleading. Setting GLOBIGNORE to a non-empty value turns on dotglob and makes that . and .. are never matched (like in other sensible shells like zsh, fish, pdksh and derivatives) even if you turn dotglob back off afterwards. (GLOBIGNORE=:; shopt -u dotglob; echo .* won't output . and ..). setting GLOBIGNORE to .:.. or . or : have the same effect. – Stéphane Chazelas Feb 21 at 19:37
    
ksh93 always ignoring . and .. seems to have been broken in between ksh93k+ (where it worked) and ksh93m (where it no longer works). Note that it's bad in that ksh93 will take the value of FIGNORE from the environment, so a FIGNORE='!(..)' env var for instance can create havoc. – Stéphane Chazelas Feb 21 at 21:05
1  
@Gilles: I can’t reproduce your results for echo .* with dotglob set in Bash 4.1.17 or 4.3.30.  With GLOBIGNORE unset, I get ., .., and all the other dot files (your output doesn’t include .).  With GLOBIGNORE set to a non-null value (even something benign like n*), I get only the ordinary dot files, and not . or .. (your output shows .. in this case).  Also, I agree with StéphaneChazelas — what’s the sense in using nullglob in the context where you used it? – G-Man Mar 28 at 6:28
    
@Gilles There is no need to set GLOBIGNORE to .:.. those values are omitted by default on any expansion when GLOBIGNORE gets set. Even a GLOBIGNORE=/+/ will omit the dot . and the double dot ... – BinaryZebra May 1 at 6:49
#!/bin/bash

shopt -s dotglob
mv Foo/* Bar/

From man bash

dotglob If set, bash includes filenames beginning with a '.' in the results of pathname expansion.

share|improve this answer
    
With the caveat that this command returns an error code if the directory was empty (even though the command actually performed as intended). – Gilles Jan 24 '11 at 20:28
    
@Gilles, the error will then be from mv complaining that that file called Foo/* doesn't exist. Interestingly, if Foo is searchable, but not readable, and there is a file called * in there, you'll get no error, that file will be moved, but not the other ones in the directory. bash has a failglob option so it behaves more like zsh, fish or csh/tcsh and abort the command with an error when a glob cannot be expanded instead of that bogus behaviour of leaving the glob as-is. – Stéphane Chazelas Feb 22 at 10:01

A simple way to do this in bash is

mv {Foo/*,Foo/.*} Bar/

But this will also move directories.

If you want to move all files including hidden but don't want to move any directory you can use a for loop and test.

for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;

share|improve this answer

One way is to use find:

find Foo/ -type f -exec mv -t Bar/ {} \+

The -type f restricts the find command to finding files. You should investigate the -type, -maxdepth, and -mindepth options of find to customize your command to account for subdirectories. Find has a lengthy but very helpful manual page.

share|improve this answer
2  
That only moves the regular files in Foo/, not subdirectories and other files. – Gilles Jan 24 '11 at 20:29

Try the copy command cp:

$ cp -r myfolder/* destinationfolder

cp -r means copy recursive, so all folders and files will be copied.

You can use the remove command rm to remove a folder:

$ rm -r myfolder

See more: move all files from a directory to another one.

share|improve this answer
1  
Not the best when you're moving a lot of large files, but I guess it would work. – Cory Klein May 12 '14 at 17:25

You might also be able to find and grep with backquotes to select files for the move command. Pass those into mv.

I.e. For hidden files

find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden

So

mv `find Foo -maxdepth 1 | egrep '^Foo/[.]'` Bar # mv Foo/.hidden Bar

Moves only selected hidden files into Bar:

mv `find Foo -maxdepth 1 | egrep '^Foo/.'` Bar # mv Foo/.hidden Foo/notHidden Bar

Moves all files in Foo to Bar since the '.' in the egrep command acts as a wildcard without the square brackets.

The ^ character ensures the match starts from the beginning of the line.

Some details of egrep pattern matching can be found here.

Using maxdepth 1 stops find from going into subdirectories.

share|improve this answer

Inspired from this answer:

Without copying the files...

rsync -ax --link-dest=../Foo/ Foo/ Bar

Caveats:

  • --link-dest path must be absolute or relative to DESTINATION (Bar in the example)

  • You've to put / after SOURCE (Foo/ in the example), otherwise it will copy the SOURCE folder instead of contents of it.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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