Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This question already has an answer here:

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 and file2.pdf are copied into the this_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 to

cp 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.

share|improve this question

marked as duplicate by Gilles, jasonwryan, Michael Kjörling, slm, Anthon Aug 6 '13 at 6:27

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

1  
Run echo cp *.pdf to see what gets executed. You omitted nothing. –  manatwork Aug 5 '13 at 14:49
19  
The answer to "have I found a bug?" when you are seeing weird behavior in a basic utility like cp, with somewhere around 99% certainty, is "no". If it was a bug, you'd almost certainly not be the first to run into it; while existing features might be exercised rarely, it's pretty safe to say that anything new will be thoroughly tested by the developers. –  Michael Kjörling Aug 5 '13 at 15:12
2  
Principle of least surprise? What should ls *.pdf expand to in such a scenario, or for f in *.pdf; do ... done? I'd prefer wildcards expand to the same things regardless of command. –  Michael Kjörling Aug 5 '13 at 19:40
1  
So 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 named all.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!) –  Michael Kjörling Aug 5 '13 at 19:51
1  
Which 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. –  Michael Kjörling Aug 5 '13 at 20:07
show 7 more comments

5 Answers 5

up vote 39 down vote accepted

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.

share|improve this answer
5  
s/bash/shell/g –  progo Aug 6 '13 at 4:15
add comment

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.

share|improve this answer
    
But 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". –  Dennis Williamson Aug 5 '13 at 18:08
    
@DennisWilliamson yes indeed, but it gives the error the OP expected, hence it displays the expected behavior. –  terdon Aug 5 '13 at 20:40
add comment

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.

share|improve this answer
2  
This could also be a great demonstration of why you should use ls and not ls *. –  Kevin Aug 6 '13 at 0:20
add comment

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
    
share|improve this answer
add comment

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
share|improve this answer
    
The problem is that I ran cp *.pdf ... not cp *.pdf this_is_a_folder.pdf –  user1598390 Aug 5 '13 at 14:52
6  
@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. –  Lekensteyn Aug 5 '13 at 14:55
1  
@user1598390: Why is that a problem? (Or: why is that unexpected?) –  LarsH Aug 5 '13 at 19:07
add comment

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