How do you move all files (including hidden) from one directory to another?
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/
#!/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.
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.
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
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.
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;
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
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.
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.
Answer for bash/fish
Here’s a way to do it using wildcards:
.[!.]* ..?*
will match all hidden files except .
and ..
.[!.]* ..?* *
will match all files (hidden or not) except .
and ..
And to answer the particular example of this question you need cd foo && mv .[!.]* ..?* * ../bar
Explanation
.[!.]*
matches file-names starting with one dot, followed by any character except the dot optionally followed by any string. This is close enough but it misses files starting with two dots like ..foo
. To include such files we add ..?*
which matches file-names starting with two dots, followed by any character, optionally followed by any string.
Test
You can test these wildcards with the commands below. I’ve tried them successfully under bash and fish. They fail under sh, zsh, xonsh.
mkdir temp
cd temp
touch a .b .bc ..c ..cd ...d ...de
ls .[!.]* ..?*
# you get this output:
.b .bc ..c ..cd ...d ...de
# cleanup
cd ..
rm -rf temp
Rsync is another option:
rsync -axvP --remove-source-files sourcedirectory/ targetdirectory
This works because in rsync the trailing slash matters, sourcedirectory/
refers to the content of the directory, while sourcedirectory
would refer to the directory itself.
The disadvantage of this method is that rsync will only cleanup the files after the move, not the directory. So you are left with an empty sourcedirectory tree. For workarounds for that, see:
Move files and delete directories with rsync?
So while this might not be optimal for move operations, it can be extremely useful for copy operations.
I find that this works well for bash and there’s no need to change shell options
mv sourcedir/{*,.[^.]*} destdir/
EDIT:
So as G-man stated, my original answer is not posix compliant and is pretty much the same as ndemou’s answer above with one change, which is to use brace expansion to create lists of strings which are then acted on. This just means you don’t need to cd
into the source directory. Not that big a change really, but it is different.
example: let’s say you have the following layout already.
$ tree -a
.
├── destdir
└── sourcedir
├── ..d1
├── ..d2
├── ..double
├── file-1
├── file-2
├── .hidden-1
├── .hidden-2
├── ...t1
└── ...t2
The original question only mentioned hidden files with a single period, but let’s say there are some with two or more periods at the start of the name. You can just add in an additional expression into the braces. We can then execute
mv sourcedir/{*,.[!.]*,..?*} destdir/
This gets expanded to the following:
mv sourcedir/file-1 sourcedir/file-2 sourcedir/.hidden-1 sourcedir/.hidden-2 sourcedir/..d1 sourcedir/..d2 sourcedir/..double sourcedir/...t1 sourcedir/...t2 destdir/
You should now see all files located in destdir:
$ tree -a
.
├── destdir
│ ├── ..d1
│ ├── ..d2
│ ├── ..double
│ ├── file-1
│ ├── file-2
│ ├── .hidden-1
│ ├── .hidden-2
│ ├── ...t1
│ └── ...t2
└── sourcedir
You can do some pretty cool things with braces in bash with even more additions in 4.x. Check out bash-hackers for some nifty examples.
For minimal Linux distros, the following ought to work. First, perform a basic move all (which misses the hidden files). Then, move all the hidden files (including the .
and ..
which will not actually be moved).
mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null
Notes: If there is no visible content, the first command will produce an error message. The second command will always produce an error saying it can’t move .
and ..
. As such, just pipe the errors into /dev/null
(as shown).
If you need this as a one-liner, simply combine them with a semi-colon:
mv /sourceDir/* /destinationDir 2> /dev/null; mv /sourceDir/.* /destinationDir 2> /dev/null
Short answer:
This is the most reliable method. It can digest any number of files:
find folder2 -name '*.*' -exec mv {} folder ;
-exec
runs any command, {}
inserts the filename found, ;
marks the end of the exec command.
Thanks to Karl Bielefeldt: https://stackoverflow.com/a/11942473/4845952