Subject: Re: bug#20603: Possible bug in cp

From: Bob Proulx <[email-masked]>
Date: Mon, 18 May 2015 17:24:17 -0600

Chris Puttick wrote:
> In moment of tiredness issued a cp command similar to
> cp /path/to/files/*
> neglecting to add a destination (should have been ./)
> The files in the directory were 2 vdisks both ending .qcow2.

Ouch!  I am sorry for your loss.  I hope you had backups. :-(

> No error message was generated and the apparent result of running the
> command is that the file whose name came first alphabetically was
> copied over the other.

There was no error message because as far as the computer was
concerned it did exactly as you instructed it and no error occurred.

You are apparently not aware that the shell reads your command line,
parses it, expands it, and then the shell executes the resulting
command.  Many command line characters are "shell metacharacters".
Search for that and you will find many references.  When I say shell
here I will assume the bash shell however this part applies to all of
the Unix-like command line shells such as ksh, zsh, csh, sh and so forth.

One of the file glob characters is the "*" character.  (It is called a
file glob because the star is expanded to match a glob of files.)
Whenever you use a '*' in a command line that is an instruction to the
shell.  It tells the shell to list the files and match them and
replace the star character with the list of matching file names.  Try
this exercise to understand a little bit about the '*' character and
what the shell does.

  $ mkdir /tmp/junk
  $ cd /tmp/junk
  $ touch file1
  $ echo *
  file1
  $ touch file2
  $ echo *
  file1 file2
  $ touch file 3
  $ echo *
  file1 file2 file3
  $ echo *1
  file1
  $ echo *[23]
  file2 file3

As you can see the shell is replacing the '*' character with the files
that were expanded which match it.  And I threw in another couple of
file expansions too just to help push the concept home.

By this point you should know that your cp command had a '*' in the
command line.  The shell expanded that star.  There were only two
expansions.  Therefore the shell invoked cp with two arguments.

  cp /path/to/files/file1 /path/to/files/file2

That is the command that cp was invoked with after the shell expanded
the file globs on the command line.  As far as the cp command is
concerned it was given a command, cp executed the command, and the
command was completed without error.

The cp command has no way of knowing that you wanted to execute this
command instead.

  cp /path/to/files/file1 /path/to/files/file2 ./

How could it?  It can't.  One command looks just the same as the other
one to the cp command.  None of the commands ever see the '*'
character because it is expanded by the shell and replaced before the
utility is invoked.

Hope that expansion helps explain things.

Bob