Situation :
$ mkdir foo && touch foo/.test
$ cp foo/* .
zsh: no matches found: foo/*
(or bash : cp: cannot stat ‘foo/*’: No such file or directory)
I have a directory full of hidden folders and files. What is happening and what is the solution?
Situation :
$ mkdir foo && touch foo/.test
$ cp foo/* .
zsh: no matches found: foo/*
(or bash : cp: cannot stat ‘foo/*’: No such file or directory)
I have a directory full of hidden folders and files. What is happening and what is the solution?
With zsh
, the typical way is to use the D
glob qualifier (to include [D]ot files):
cp foo/*(D) .
Note that with or without D
, zsh globs never include .
nor ..
(as you'd expect).
Disclaimer: This answer deals with Bash specifically but much of it applies to the question regarding glob patterns!
The star character (*
) is a wildcard. There are a certain set of characters that it will take the place of and the first character being a dot (.
) isn't one of them. This is a special case just because of how the Unix filesystems work, files that start with a dot are considered "hidden". That means that tools such as cp
, ls
, etc. will not "see" them unless explicitly told to do so.
First let's create some sample data.
$ mkdir .dotdir{1,2} regdir{1,2}
$ touch .dotfile{1,2} regfile{1..3}
So now we have the following:
$ tree -a
.
|-- .dotdir1
|-- .dotdir2
|-- .dotfile1
|-- .dotfile2
|-- regdir1
|-- regdir2
|-- regfile1
|-- regfile2
`-- regfile3
Now let's play some games. You can use the command echo
to list out what a particular wildcard (*
) would be for a given command like so:
$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3
$ echo reg*
regdir1 regdir2 regfile1 regfile2 regfile3
$ echo .*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2
$ echo .* *
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
$ echo .dotdir*
.dotdir1 .dotdir2
You can use the command shopt -s dotglob
to change the behavior of the *
so that in addition to files like regfile1
it will also match .dotfile1
.
excerpt from the bash
man page
dotglob If set, bash includes filenames beginning with a `.' in the results
of pathname expansion.
Example:
$ shopt -s dotglob
$ echo *
.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
You can revert this behavior with this command:
$ shopt -u dotglob
$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3
For you you're telling cp
that you want to copy all the files that match the pattern *
, and there aren't any files.
$ cp foo/.* .
Or you can do this if you want everything in the foo
folder:
$ cp foo .
Or you can be explicit:
$ cp foot/.* foo/* .
A more compact form using brace expansion in bash
:
$ cp foo/{.,}* .
At any time you can use the echo
trick to see what your proposed file patterns (that's the fancy term for what the star is a part of).
$ echo {.,}*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 abc regdir1 regdir2 regfile1 regfile2 regfile3
Incidentally if you're going to copy a directory of files + other directories, you typically want to do this recursively, that's the -R
switch to cp
:
$ cp -R foo/. .
shopt -s dotglob
, echo *
then gives: .dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
– Drav Sloan
Sep 07 '13 at 09:32
cp -r foo .
will typically not work since cp
will refuse to copy foo
over itself, you probably meant cp -R foo/. .
. (note that cp -R
is the standard one).
– Stéphane Chazelas
Sep 07 '13 at 15:00
zsh
doesn't include .
and ..
in the expansion of .*
. In zsh
, if a pattern doesn't match, the command is aborted (quite sensibly again), so in the general case, cp foo/{,.}* .
will fail if there's no hidden or no non-hidden files.
– Stéphane Chazelas
Sep 07 '13 at 15:04
cp
man page it shows this: -R, -r, --recursive
. I would take that to mean that any form of the switch is acceptable.
– slm
Sep 07 '13 at 15:07
zsh
, still prefer bash
even with all its warts.
– slm
Sep 07 '13 at 15:09
cp
. GNU stands for GNU's Not Unix
. Here, we're on Unix and Linux
, Unix
being in the largest sense of the word a family of operating systems and Linux the kernel found in a number of Unix-like operating systems. As such, GNU cp
is just one of many implementations of the standard Unix cp
command. The specification of the standard cp
can be found here
– Stéphane Chazelas
Sep 07 '13 at 15:44
shopt
doesn't exist.
– Gilles 'SO- stop being evil'
Sep 07 '13 at 21:56
.
meaning hidden files has nothing to do with Unix file systems. That's just a convention in applications.
– Stéphane Chazelas
Sep 17 '15 at 10:42
The shell is treating those files as hidden when it resolves the *
character, so cp
doesn't receive any of these file names as arguments.
You can copy them by explicitly specifying cp foo/.* .
If what you're wanting to do is copy all files & directories from one place to another, you could use the standard rsync
command. In the example you give above:
mkdir foo && touch foo/.test
rsync -a foo/ .
will recursively copy all of the contents of foo
, including hidden files and hidden directories, into the current directory. The trailing slash at the end of foo/
is important to rsync; with it only the contents of foo
are copied, without it rsync will copy foo
as well. For example:-
mkdir src && mkdir dest && touch src/.test
rsync -a src dest // copies 'src' contents to 'dest/src'
rsync -a src/ dest // copies 'src' contents to 'dest'
There are many other options available tweak rsync, including copying between machines.
dotglob
is translated toglobdots
by [tag:zsh] which is invalid option name for [tag:bash]. – Aug 27 '17 at 17:21