3

I just became really confused by the implementation of bash's cp -R command compared to how POSIX words what should happen

Given the posix definition, I would expect cp -R srcDir existingDestDir to result in the contents of srcDir to be copied into the existingDestDir. Instead srcDir gets copied into existingDestDir both in bash and csh implementations of sh.

The relevant portion of the posix cp -R definition:

For each source_file, the following steps shall be taken:

(...)

2. If source_file is of type directory, the following steps shall be taken:

(...)

f. The files in the directory source_file shall be copied to the directory dest_file, taking the four steps (1 to 4) listed here with the files as source_files.

I would appreciate it greatly if someone could clear this up for me.

3
  • 6
    cp is an external binary, so it has nothing to do with the shell. Perhaps you mean GNU's cp implementation?
    – jordanm
    Jan 25 '15 at 3:31
  • I see - thanks a ton. I had the incorrect impression that posix loosely translated to portability. That and realizing cp comes from the coreutils library (from your gnu statement) helped me past my mental block.
    – aaaaaa
    Jan 25 '15 at 4:01
  • I don't have enough reputation to upvote comments, but if either of you care enough to write an answer (albeit for a confusing question), I will mark it as correct. I'm only a year into using linux and am still trying to grasp some fundamental concepts.
    – aaaaaa
    Jan 25 '15 at 19:03
3

You missed a paragraph further up in the POSIX document:

The third synopsis form (cp -R [-H|-L|-P] [-fip] source_file... target) is denoted by two or more operands where the -R option is specified. The cp utility shall copy each file in the file hierarchy rooted in each source_file to a destination path named as follows:

  • If target exists and names an existing directory, the name of the corresponding destination path for each file in the file hierarchy shall be the concatenation of target, a single <slash> character if target did not end in a <slash>, and the pathname of the file relative to the directory containing source_file.

In your case, with

cp -R srcDir existingDestDir

The "source_file" is srcDir and "target" is existingDestDir. With the paragraph, the "destination path for each file in the file hierarchy" becomes existingDestDir/srcDir, which explains the behaviour you are seeing.

4
  • I appreciate you pointing that out because I did miss that. Still confused though because 2 -> a specifies If the -R option was not specified, cp shall write a diagnostic message implying -R is covered in the following steps. This means that somehow your quote overrides the steps I quoted. I'll chalk it off as being confusing (free) documentation that I am not accredited to rewrite.
    – aaaaaa
    Jun 22 '16 at 16:14
  • 1
    @aaaaaa Not confusing. I think you are mixing up target with dest_file in the standard document: "If target exists and names an existing directory, the name of the corresponding destination path for each file in the file hierarchy shall be [target/source_file]"... "In the following description, the term dest_file refers to the file named by the destination path."
    – Kusalananda
    Jun 22 '16 at 16:26
  • You're right. I'm sorry for the confusion as I know a confused question is difficult to answer. Re-reading the document now it makes a lot more sense.
    – aaaaaa
    Jun 22 '16 at 16:33
  • 1
    @aaaaa Now try cp -R srcDir/ existingDestDir and ask another question ;-)
    – Kusalananda
    Jun 22 '16 at 16:34
2

There are several points to clear up:

  • cp is a separate utility from bash. Some people may be confused by built-in commands such as cd and pwd which either are or may be part of a POSIX shell.
  • POSIX refers to the series of documents jointly maintained by The Open Group and the IEEE, referred to as IEEE Std 1003.1™.
  • bash is one of several shells which implement the features described in POSIX. Most shells have some differences from the POSIX shell sh; the name by which the shell is run is a feature described in POSIX.
  • in the section 2.14. Special Built-In Utilities, POSIX says

The term "built-in" implies that the shell can execute the utility directly and does not need to search for it. An implementation may choose to make any utility a built-in; however, the special built-in utilities described here differ from regular built-in utilities in two respects:

So in principle cp could be a part of bash if its developers had chosen to do that. In practice this is not done because there is no point in further complicating bash by adding features that can be done well separately from bash.

Next, the link mentioned in the question is based on POSIX, but is not the POSIX document. You can see the disclaimers at the end:

Portions of this text are reprinted and reproduced ...

and

Any typographical or formatting errors that appear in this page are most likely to have been introduced during the conversion of the source files to man page format.

But most of the manual page is copied word-for-word from POSIX. POSIX documents are written in a quasi-legalistic style, attempting to avoid describing things in detail where its authors are aware that existing implementations differ, as well as avoid detail where they believe that implementation internal details may differ. So what you get is a step-by-step description of actions that the programs take, and (often) omitting details which other authors would add to explain how the different steps are related. Some of the POSIX documents provide a section for RATIONALE, but even those seem to be a minority. The result is often vague, but you have to make allowances for the intent: describing common features of existing programs.

This is the specific part of the question which indicates confusion:

Given the posix definition, I would expect cp -R srcDir existingDestDir to result in the contents of srcDir to be copied into the existingDestDir. Instead srcDir gets copied into existingDestDir both in bash and csh implementations of sh.

The point of the documentation is that directories in the source are also handled using the same iterative and recursive description as ordinary files. One of the rules is outlined in the Synopsis section:

cp -R [-H|-L|-P] [-fip] source_file... target

which is the third example, and the only one mentioning the -R option. This is referred to later, in the Description:

The third synopsis form is denoted by two or more operands where the -R option is specified. The cp utility shall copy each file in the file hierarchy rooted in each source_file to a destination path named as follows:

  • If target exists and names an existing directory, the name of the corresponding destination path for each file in the file hierarchy shall be the concatenation of target, a single <slash> character if target did not end in a <slash>, and the pathname of the file relative to the directory containing source_file.

  • If target does not exist and two operands are specified, the name of the corresponding destination path for source_file shall be target; the name of the corresponding destination path for all other files in the file hierarchy shall be the concatenation of target, a <slash> character, and the pathname of the file relative to source_file.

That is, your directory name is treated as a "file" in the first bulleted item, and is concatenated with the target directory's name.

Further reading:

The GNU coreutils manual page lacks detail. You can see some of the flavor of the POSIX document in the Solaris manual page, which by the way is more clearly written:

/usr/bin/cp -r | -R [-H | -L | -P] [-fip@] source_dir... target

and

In the third synopsis form, one or more directories specified by source_dir are copied to the directory specified by target. Either -r or -R must be specified. For each source_dir, cp copies all files and subdirectories.

1
  • I can't thank you enough for writing all that information. It helps my understanding greatly. Please put a 'donate' button in your profile so I can buy you a couple beverages.
    – aaaaaa
    Jun 22 '16 at 16:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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