cp with a single argument containing wildcards
Solution 1
This is not a bug in the cp
command. When you enter cp *.pdf
, cp
never sees the actual wildcards because the wildcards are expanded by bash
, not by cp
. How will cp
know that you have entered only one argument? This is a side effect of bash wildcards and cannot be called a bug.
Solution 2
You seem to understand what is happening perfectly well. In your example, *pdf
indeed expands to file1.pdf file2.pdf this_is_a_folder.pdf
. I don't see what's confusing you. cp
is doing exactly what it should, you are telling it to copy file1.pdf
and file2.pdf
into this_is_a_folder.pdf
and that is exactly what it is doing. There is no bug, it is working as advertised.
Since your folder's name ends in .pdf
, it is included in *.pdf
and since it is a folder and the last argument (sorted alphabetically), cp
copies the files into it. To get the behavior you expect, you need to protect the wildcard from the shell so it is not expanded before cp
sees it:
$ cp "*pdf"
cp: missing destination file operand after `*pdf'
Try `cp --help' for more information.
Note that in this case, the wildcard is not expanded so cp
is actually looking for a file called *.pdf
. So even if you were to call it with a directory as the last argument (cp "*.pdf" foo/
) it would complain about cannot stat '*.pdf': No such file or directory
. You will also see your expected behavior if you try cp *pdf
in a directory that only contains one file that ends in .pdf
because *.pdf
will be expanded to only one argument:
$ ls -l
total 0
-rw-r--r-- 1 terdon terdon 0 Aug 5 16:56 file1.pdf
$ cp *pdf
cp: missing destination file operand after `file1.pdf'
Try `cp --help' for more information.
Also compare with this:
$ ls -l
total 0
drwxr-xr-x 1 terdon terdon 0 Aug 5 16:56 a_folder.pdf
-rw-r--r-- 1 terdon terdon 0 Aug 5 16:56 file1.pdf
-rw-r--r-- 1 terdon terdon 0 Aug 5 16:56 file2.pdf
$ cp *pdf
cp: target `file2.pdf' is not a directory
Here, since the folder's name begins with an a
, *.pdf
is expanded to:
a_folder.pdf file1.pdf file2.pdf
. Therefore, the cp
command actually being run is
cp a_folder.pdf file1.pdf file2.pdf
Which returns an error because the last argument is not a directory.
Solution 3
As the other answers already pointed out, bash expands the wildcard and then passes what it sees to cp
. In your case, cp
sees file1.pdf file2.pdf this_is_a_folder.pdf
. Now let's prevent it.
- Don't use wildcards.
- Use the
-t
,--target-directory
switch and specify the target. Always declare at the very end a destination after using a wildcard.
cp *.pdf /I/want/to/copy/files/here
Solution 4
It's not a bug, it's a side-effect doing of wildcard expansion once in the shell rather than implementing it in every program.
Now, there are some much stranger ways you can trip yourself up with this, especially by creating files whose names start with "-". For example (in an empty directory):
$ touch -- --version
$ ls
--version
$ rm *
rm (coreutils) 5.2.1
Written by Paul Rubin, David MacKenzie, Richard Stallman, and Jim Meyering.
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ ls
--version
The wildcard '*' expands to the filename which gets interpreted as a switch.
You can also cause chaos by putting spaces, tabs and newlines in file names.
Solution 5
If the last part parameter is a directory, cp
will copy the specified files to it. It does not care if you named your directory foo.pdf
(why such a name?!). Wildcard expansion is based on the file name (or directory name), not the file type.
With two arguments, the target can be either a file or directory. In the case of a file, the target file is removed and replaced by a copy of the source file. If the target is a directory, a copy of the source file is placed in that directory. Note one of the given synopsis:
cp [OPTION]... [-T] SOURCE DEST
With three or more arguments, the target is treated as a directory:
cp [OPTION]... SOURCE... DIRECTORY
Related videos on Youtube
![Tulains Córdova](https://i.stack.imgur.com/RQ8O6.png?s=256&g=1)
Tulains Córdova
I seek not to know all the answers, but to understand the questions. - Kwai Chang Caine I've been programming for more than two decades. I specialize in database design, SQL, PL/SQL, Unix Shell Scripting, Java SE, OOP, OOD, good practices, SOLID principles, software patterns and code quality. Manipulating and processing data with scores of different tools is something I do often. I've done extensive work automating routinary tasks by leveraging Shell Scripting. I like to improve software usability and user experience. Fledgling DBA with 6 years of experience but with an awful lot to learn. Spanish is my mother tongue and I'm fluent in english. I can read technical french.
Updated on September 18, 2022Comments
-
Tulains Córdova almost 2 years
If I have the following 2 files and 1 folder:
someuser@computer:~/Desktop/test$ ls -l total 340 -rw-r--r-- 1 someuser someuser 45082 ago 5 09:56 file1.pdf -rw-r--r-- 1 someuser someuser 291836 ago 5 09:56 file2.pdf drwxrwxr-x 2 someuser someuser 4096 ago 5 09:56 this_is_a_folder.pdf
And I run the following command (notice that I ommit the destination):
cp *.pdf
file1.pdf
andfile2.pdf
are copied into thethis_is_a_folder.pdf
folder.someuser@computer00:~/Desktop/test$ ls this_is_a_folder.pdf/ file1.pdf file2.pdf
Obviously
*.pdf
is expanding into matching items, so it's equivalent tocp file1.pdf file2.pdf this_is_a_folder.pdf
... and as
this_is_a_folder.pdf
is a folder, then the two files are copied to it.Is this a bug ?
It's obviously a side effect of wildcard expansion and it's not what I would expect to happen.
I would have expected a
missing destination file
error.-
manatwork almost 11 yearsRun
echo cp *.pdf
to see what gets executed. You omitted nothing. -
LarsH almost 11 yearsYou understand what the shell's wildcard expansion is doing. Why then would you have expected a
missing destination file
error? -
Tulains Córdova almost 11 years@LarsH Principle of less surprise ? I understand that after it happend to me, not defore.
-
user almost 11 yearsPrinciple of least surprise? What should
ls *.pdf
expand to in such a scenario, orfor f in *.pdf; do ... done
? I'd prefer wildcards expand to the same things regardless of command. -
Tulains Córdova almost 11 years@MichaelKjörling The expanding is OK, but obviously a person that executes
cp *.pdf
is not expecting it to copy some files to an uknown folder. -
user almost 11 yearsSo how would
cp
know that you used shell wildcard globbing? How would it know that you want some behavior different from e.g.ls
? What if you really wanted to copy all files and subdirectories with names ending in .pdf into a subdirectory namedall.my.pdf
? Comments aren't meant for discussion, but I'd say it is far from "obvious" that what you are proposing is better or more reasonable to expect. (I for one rather memorize one rule, that any wildcard glob will expand to everything that glob matches and I better deal with it, than one rule per command!) -
Tulains Córdova almost 11 years@MichaelKjörling I used to see it like this: in
cp *.pdf dest_folder
,*.pdf
is the SOURCE anddest_folder
is the DESTINY. If I accidentally rancp *.pdf
, I ommitted the DESTINY, and only provided the SOURCE, which should raise an error. -
user almost 11 yearsWhich it would have, if
*.pdf
had not expanded to include a valid destination location at the end of the list, as exemplified in the answers already. -
LarsH almost 11 years"Principle of least surprise" is a valid point, but it begs the question, why should that behavior be surprising? And yes I can see why it surprised you at first, especially if you didn't know that wildcards are expanded separately by the shell; but, given that fact, it's certainly not a bug in cp, and it's hard to see how cp could be designed differently to decrease surprise. Changes that would decrease surprise would be (a) don't name a directory
something.pdf
; (b) don't use a wildcard pattern, such as*.pdf
, that could match an existing directory; or (c) use-t
as @Braiam said. -
Tulains Córdova almost 11 years@LarsH Something is certain: If it happens again, I will no longer be surprised.
-
Carlos Campderrós almost 11 yearsa shell (
bash
,sh
,zsh
, ...) is a command line interpreter, so it interprets your commands and then executes them. So the command you typed is not always the command that will be executed. And the real command can't know what did you really type (in this instance,cp
only seesfile1.pdf
,file2.pdf
andthis_is_a_folder.pdf
, not your wildcard.
-
-
Lekensteyn almost 11 years@user1598390 Glob expansion is done by the shell, therefore
this_is_a_folder.pdf
is implied by*.pdf
.cp
does not know that you only want to copy a set of files. -
Brian Rasmussen almost 11 yearsBut by using quoting in
cp "*pdf"
, even if you included a destination argument, the asterisk never gets expanded and you will get a "no such file" message unless you have one named literally "*pdf". -
LarsH almost 11 years@user1598390: Why is that a problem? (Or: why is that unexpected?)
-
terdon almost 11 years@DennisWilliamson yes indeed, but it gives the error the OP expected, hence it displays the expected behavior.
-
Kevin almost 11 yearsThis could also be a great demonstration of why you should use
ls
and notls *
. -
mike3996 almost 11 years
s/bash/shell/g