3

I find myself doing this often enough that I wonder if there's a standard Unix way to do it:

% mkdir -p /TARGETDIR/relative/path/to
% cp ./relative/path/to/somefile /TARGETDIR/relative/path/to

In other words, I don't want to just copy somefile to /TARGETDIR, but actually I want to copy its entire relative path.

Is there a simpler way to do this than the two-liner above?

2
  • 1
    you could use rsync to "mirror" one directory/filesystem to the other (including structure)
    – h3rrmiller
    Mar 5, 2013 at 20:15
  • @h3rrmiller How do you propose to do that (in a way that isn't cp -R relative /TARGETDIR)? Mar 5, 2013 at 23:29

2 Answers 2

6

With GNU coreutils (non-embedded Linux, Cygwin):

cp -p --parents path/to/somefile /TARGETDIR

With the POSIX tool pax (which many default installations of Linux unfortunately lack):

pax -rw -pp relative/path/to/somefile /TARGETDIR

With its traditional counterpart cpio:

find relative/path/to/somefile | cpio -p -dm /TARGETDIR

(This last command assumes that file names don't contain newlines; if the file names may be chosen by an attacker, use some other method, or use find … -print0 | cpio -0 … if available.)

Alternatively, you could make it a shell script or function.

cp_relpath () {
  mkdir -p -- "$2/$(dirname -- "$1")"
  cp -Rp -- "$1" "$2/$(dirname -- "$1")"
}
10
  • I'd say that cp's -p is irrelevant to the matter of the question (as well as writing scripts/programs is obviously redundant — actually I'm tempting to see another "answer" with version in Fortran, Cobol and Haskel, may be).
    – poige
    Mar 6, 2013 at 13:34
  • @poige It isn't, but usually the option is desirable, so I include it by default. Mar 6, 2013 at 13:36
  • "Usually" != "really needed in question"
    – poige
    Mar 6, 2013 at 13:37
  • So, to conclude — the only difference between our answers really worth mentioning was pax "which many default installations of Linux unfortunately lack". Entropy thanks you, чо.
    – poige
    Mar 6, 2013 at 13:41
  • 1
    @poige Besides cp --parents, I wanted to mention pax and cpio for the non-Linux audience, and show how to do it with a function. Mar 6, 2013 at 15:47
4

man cp reveals --parents. So simple, yeah.

$ mkdir /tmp/myetc && cp --parents init.d/cron /tmp/myetc && find /tmp/myetc/
/tmp/myetc/
/tmp/myetc/init.d
/tmp/myetc/init.d/cron
1
  • 1
    Note that --parents is a GNUism (it is only a long version flag).
    – vonbrand
    Mar 5, 2013 at 22:13

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.