NHacker Next
  • new
  • past
  • show
  • ask
  • show
  • jobs
  • submit
▲cp: -r or -R? (movq.de)
bariumbitmap 19 hours ago [-]
This blog post is odd because it keeps on hinting about a difference between `-r' and `-R' and links to the source code but never actually says what it is. I'll quote the OpenBSD manual that the post mentions but does not link to for some reason:

> Historic versions of the cp utility had an -r option. This implementation supports that option; however, its use is strongly discouraged, as it does not correctly copy special files, symbolic links or FIFOs.

https://man.openbsd.org/cp

embedding-shape 18 hours ago [-]
> links to the source code but never actually says what it is.

The snippet of code makes it very clear what the difference is, no?

flag_copy_as_regular = 1 VS flag_copy_as_regular = 0, where regular would be a "regular" and not "special" file.

spijdar 19 hours ago [-]
> nobody™ still runs coreutils from 24 years ago.

  Sprite 2.077 pc386
  
          Welcome to Sprite
  
  root@cherimoya [1] # cp --version
  GNU fileutils 3.9
  root@cherimoya [2] # cp --help | grep recurs
    -r                           copy recursively, non-directories as files
    -R, --recursive              copy directories recursively
  root@cherimoya [3] #
I'll take the honorary title of nobody ;-)
collinfunk 3 hours ago [-]
Hey, I perfectly understand if not. But do you have the sources that were used to build those binaries?

The oldest version on the GNU ftp server is fileutils-3.13 [1]. I vaguely remember having some links to older versions, probably somewhere in my archived mail. But I don't remember if it was fileutils-3.9 or earlier.

I co-maintain GNU coreutils, so I am interested in reading them. If you have them, you can email me privately or on the public mailing list. Both are listed on the homepage [2].

[1] https://ftp.gnu.org/old-gnu/fileutils/ [2] https://www.gnu.org/software/coreutils/

kijin 18 hours ago [-]
You should have run that command as the `nobody` user.
tosti 10 hours ago [-]
But nobody doesn't have a valid shell.
kijin 4 hours ago [-]
Nothing you can't fix if you have root. :)
mkl 19 hours ago [-]
-a

Not sure why you wouldn't want to preserve timestamps, links, etc. by default.

JdeBP 19 hours ago [-]
This is rather missing the point. The headlined article isn't really about how to achieve a goal, but about the weird history and evolution of a tool that leads us to the rather odd situation that we are in today. And it's far from being the only tool that has a weird history, that looks rather nutty if one looks at it from the point of view of a novice having to learn this stuff.

It's also not even completely covering the weird case of -r and -R for the cp command. On HP-UX, for example, the twain were different, but not in the way that they were in old GNU Core Utilities. That would be too easy. (-:

The AIX manual for cp explains its difference between -r and -R:

* https://ibm.com/docs/en/aix/7.1.0?topic=c-cp-command

Illumos also treats the two differently, but in a subtly different way:

* https://illumos.org/man/1/cp

Joker_vD 18 hours ago [-]
That's why, just as fork(2) is a primitive for the process creation, copy(2) should've been the primitive for the file creation — creates an exact copy of the file under a new name, but with the exact same content and all of the metadata (except for the name, obviously), including its kind, permissions, timestamps, etc. And no, it wouldn't be prohibitively expensive because all filesystems can quite easily support CoW; after all, most of the created files will be truncate(2)d almost immediately, so there is no point to eagerly duplicate the file contents.

The "metadata is atomically copied" part would support very nicely the usual text editor's idiom of rename(2)ing a temporary file over the source after fully writing it out — you still need to accurately replicate the permissions and extended attributes. And just as shells are important enough programs to have fork(2) almost exactly suited for them, it would make sense to have copy(2), suited for the text editors.

JdeBP 18 hours ago [-]
When cp was invented, 'most filesystems' did not have the first clue about copy on write.

However, I should note that possibly the first company to invent what you describe was Microsoft.

Novell Netware 386 had an NCOPY command which invoked a Netware extension to the DOS API that told the server to perform the entire copy on the server.

But even earlier, OS/2 1.x had a proper DosCopy() system call. Since it could be passed down to the installable filesystem drivers for intra-volume copies, something like the Netware client for OS/2 could in theory turn it into the same protocol call that did server-side copies. There was a NET COPY command in LAN Manager (and LAN Server, if memory serves) that did the same optimization.

* https://www.edm2.com/index.php/DosCopy_(OS/2_1.x)

* https://www.edm2.com/index.php/FS_COPY

Joker_vD 18 hours ago [-]
> When cp was invented, 'most filesystems' did not have the first clue about copy on write.

Eh, when fork was invented, most (virtual) memory systems did not have the first clue about copy-on-write either. And honestly, it's really not that difficult to support — it's essentially hard links, just with slightly different semantics.

collinfunk 3 hours ago [-]
In theory, I agree that it shouldn't be tricky. However, in practice, it is a bit tricky since all the different implementations have different ways to perform reflinks.

Linux has FICLONE [1], which I prefer because it operates on two file descriptors, allowing you to safely modify file metadata after the fact. macOS has clonefile, clonefileat, and fclonefileat [2]. Sadly, there is no way to operate on two file descriptors. The best you get is fclonefileat, which operates on a source file descriptor. Solaris has reflink and reflinkat, which operate on two paths, the latter relative to file descriptors [3]. In that case, one needs to be careful opening the destination to make changes to the metadata.

GNU coreutils has support for reflinks on Linux and macOS. But I've been thinking about adding support for Solaris as of late [4]. Sadly, I don't use it enough to test it as much as I would like.

Hopefully, a few years down the line the interfaces converge, and it is as simple as hard linking.

[1] https://man7.org/linux/man-pages/man2/FICLONE.2const.html [2] https://www.manpagez.com/man/2/clonefile/ [3] https://docs.oracle.com/cd/E86824_01/html/E54766/reflinkat-3... [4] https://lists.gnu.org/archive/html/coreutils/2026-09/msg0012...

emmelaich 19 hours ago [-]
old cp didn't have `-a`

Anyway, just use rsync.

dspillett 18 hours ago [-]
> just use rsync

You still need to specify --archive (or --times for the individual option) to preserve mtime in the target copy.

But yeah, I tend to rsync more than I cp.

BobMontgomeryJr 11 hours ago [-]
-h perhaps the only useful comment here. -R just looks baroque, but ls(1) might think it fine. I once read an article about the inconsistencies in *nix CLI commands, but the picture's much better than hot-key and shortcut conflicts- <which get silently absorbed by whatever's running, no way to tell what they might've done or where they went..> I hestitate to consult documentation, because of course there is non anymore. Why not Google it?
throwaway2046 19 hours ago [-]
I'm more inclined to use the uppercase -R as it's standardized by POSIX and will generally behave the same on any POSIX compliant system.
WhyNotHugo 14 hours ago [-]
It's also the only option shown in the -h output and in man pages for some versions of cp.

I didn't even know -r was a thing until today.

BobMontgomeryJr 11 hours ago [-]
there there are antisocial surprises, like YC's 'login' required after writing a post - which led me to go log into another machine, check my list, then come back here and login. Looming is the question whether a login failure would've erased what I wrote. There are of course fantasticaly more egregious UX gaffes.. imagining now [cp] and [ls] buttons .. perhaps better than 'intelligent' locator select/copy/paste madddenlingly split between kb keys and screen touches, highlighting not exactly what precisely you specify, instead crazily jumpping the selection about phrenically, while necessity of scrolling offscreen up and down further complicates - often 'select all' means 'select only whats onscreen' <surprise later, only after a paste> micro displays, big thumbs, filly 5/8ths of my present Android screen obscured by an on-screen keyboaard, even though I'm typing on a BT kb. As you might infer from this rambling paragraph I'm an OOtB ADHD wannabe-Dev type, enough at least to have heard about 'DNRY' which in sum, I'd say I hope Ai somehow obliterates <after the fashion of *nix apt's, perhaps?> with 'you can you it anyway you like - there are a dozen ways to do anything, and they all work all the time - modulo of course in reality that anti-DNRY paridigm taken beyond the UI foments chaos and confusion.
bsoqk 20 hours ago [-]
It's "ditto", not "dito"
Waterluvian 20 hours ago [-]
As in the Pokémon, not the Philippines telecom company.
Yaqub_W 19 hours ago [-]
Much easier to press a key twice than to hunt for é for most people. I get your point though
Waterluvian 19 hours ago [-]
Apparently Pokémon is in my phone’s word book.
greatgib 19 hours ago [-]
I never noticed but indeed in France the official name is "Pokémon" and not "Pokemon". So that the pronunciation in French is correct.

Is it the case in another country to have a localized name for that?

amenghra 18 hours ago [-]
Pokémon is the trademark (see e.g. https://en.wikipedia.org/wiki/Pok%C3%A9mon). Pokemon is common spelling in countries where keyboards don't have é and/or where people aren't used to inputting é.

It is common for brands to localize their names. E.g. Axe (the deodorant) in some countries is branded as Lynx.

317070 18 hours ago [-]
Pokémon has an accent in all languages: https://en.wikipedia.org/wiki/Pok%C3%A9mon
19 hours ago [-]
NaiveBayesian 19 hours ago [-]
Huh, TIL. In German, "dito" is the correct spelling, so I always figured it would be the same in English as well.
xrd 18 hours ago [-]
I really wish there was a way to know if LLMs hallucinate these switches incorrectly, like I do.

Feels like this would be exactly the kind of thing they would get wrong. Fur exactly, the training set isn't trained to know the context of execution (FreeBSD vs macos vs Linux), right?

saidnooneever 18 hours ago [-]
its trained to read both tekst and code which is enough to know the difference.

appearently i am not :') never knew there was -r

drhagen 19 hours ago [-]
It always seemed like the recursive flag of cp was an implementation detail leaking into the UI. Like, I get that copying a file requires creating more than one inode, but...so? Eventually, graphical OSes agree with me—copy/paste works the same on folders as it does on files.
dotancohen 19 hours ago [-]
Thirteen years ago I asked the same question:

https://unix.stackexchange.com/questions/82485/when-wouldnt-...

It seems that recursive by default would have been much more intuitive.

JdeBP 18 hours ago [-]
It's rather sad that none of the answers were that the cp command simply did not gain a recursive option until the 1980s, well into the 1980s if you were on one side of the Unix wars.

Yes, seriously. When you read about the supposed evils of cat -v from the Unix nostalgia people, remember that it was the same people who gave cat its -v option who also gave cp its -r option, in 4.2BSD.

It took over half a decade to percolate out of the BSD world, too. AT&T Unix System 5 did not have an -r option to cp. Here's Brandon S. Allbery explaining in 1987 how one copies directories on AT&T Unix System 5 Releases 2/3 by combining find and cpio -p:

* https://groups.google.com/g/comp.unix.questions/c/XiumTgkcYR...

Originally we read directories as raw byte streams and liked it, you know. (-:

Joker_vD 15 hours ago [-]
> When you read about the supposed evils of cat -v from the Unix nostalgia people, remember that it was the same people who gave cat its -v option who also gave cp its -r option, in 4.2BSD.

Then the people who complained about cat -v went ahead and made better Unix, called Plan 9, in which moving (as opposed to merely renaming) a directory is impossible: instead, you're supposed to do mkdir && dircp && rm -r. Which is quite a choice, if I say so myself: there is simply no low-level primitive (syscall or 9p message) for moving files across directories, even on the same file server. Their version of mv can move files across the directories, but it's still done with internal equivalent of cp+rm.

alwillis 18 hours ago [-]
ditto is an option on macOS for copying files and directories [1].

[1]: https://keith.github.io/xcode-man-pages/ditto.1.html

bdavbdav 19 hours ago [-]
This always get me. I instinctively -r, until chown which of course doesn’t take it.
5555watch 19 hours ago [-]
On a somewhat related note, I really hate that in scp -r and -R mean entirely different things.
pluc 19 hours ago [-]
The worst is when things behave different when you give them `~/somedir` vs `~/somedir/`. I think it's rsync that does that
GrantMoyer 18 hours ago [-]
I really like this feature of rsync (trailing "/" means copy the directory contents to the dest, no trailing "/" means copy the directory itself). Other tools, like cp, don't have any way at all to say copy the directory contents to the dest, and for those tools the result depends on whether or not the destination already exists and is a directory (you might end up with a duplicate nested directory). Rsync produces the same result whether the destination already exists or not.
mjmas 18 hours ago [-]
rsync, or at least the version I had would behave differently for 'rsync a b' vs 'rsync a/ b/', even though I added the slash for both sides.
IshKebab 19 hours ago [-]
And `cp`.
brewmarche 7 hours ago [-]
I remember that macOS/FreeBSD’s cp -R behaves differently depending on the trailing slash (it’s pointed out in the man page). But when I compared with GNU coreutils and busybox they did not, so it’s something to look out for.
amelius 19 hours ago [-]
Yes, into versus onto. Luckily we have AI to write our command lines.
aulin 19 hours ago [-]
How about port that is lowercase in ssh and uppercase in scp?
wanick 18 hours ago [-]
scp took -p from rcp/cp, where it already meant preserve times. So port got -P.
mqus 20 hours ago [-]
would you be safe in using --recursive always? (e.g. shell scripts)
olowe 20 hours ago [-]
There are implementations of cp out in the wild that do not recognise the --recursive flag. OpenBSD was mentioned in the article and there’s also busybox cp https://busybox.net/downloads/BusyBox.html
hnfong 19 hours ago [-]
Double dash long options are basically a GNU extension. BSD utilities generally don't support them. Apparently macOS does not either (since it's based off of FreeBSD)
JdeBP 19 hours ago [-]
macOS was based off NeXTSTEP, not FreeBSD.

And the received wisdom about long options in the BSDs is a quarter of a century out of date. When the BSDs gained a getopt_long() in their C libraries thanks to Klausner and Baron, long options quietly started appearing. This process has been gradually and quietly on-going for the whole of the 21st century.

throw0101a 19 hours ago [-]
> macOS was based off NextBSD, not FreeBSD.

"NextBSD" was first released in 2015:

* https://en.wikipedia.org/wiki/NextBSD

Over a decade after macOS/Mac OS X was initially released:

> macOS (previously OS X and originally Mac OS X) is a proprietary Unix[7][8] operating system, derived from OPENSTEP for Mach and FreeBSD, which has been marketed and developed by Apple since 2001.

* https://en.wikipedia.org/wiki/MacOS

> Darwin is the core Unix-like operating system of macOS, iOS, watchOS, tvOS, iPadOS, audioOS, visionOS, and bridgeOS. It previously existed as an independent open-source operating system, first released by Apple in 2000. It is composed of code derived from NeXTSTEP, FreeBSD[3] and other BSD operating systems,[7] Mach, and […]

* https://en.wikipedia.org/wiki/Darwin_(operating_system)

I remember reading release notes for FreeBSD in the '00s and seeing the exact same lines in the release notes for earlier versions of OS X.

alwillis 18 hours ago [-]
> Darwin is the core Unix-like operating system of macOS

macOS isn't "Unix-like"; it's an Open Group certified UNIX™ [1].

[1]: https://www.opengroup.org/openbrand/register/brand3725.htm

JdeBP 19 hours ago [-]
Bah! Thought NeXTSTEP. Typed NextBSD. Fixed. I've been typing lots of names ending in 'BSD' today. (-:
hnfong 14 hours ago [-]
I posted my original comment based off my pre-existing knowledge, but here's a more in-depth explanation of the macOS and FreeBSD situation (which aligns with my understanding):

https://www.reddit.com/r/freebsd/comments/1g07sdm/comment/lr...

Essentially, macOS was indeed based on NeXTSTEP originally, but over the years they copied quite a bit of BSD code over (mostly FreeBSD I think). I don't think the Unixy parts of the original NeXTSTEP survives much in modern macOS.

dotancohen 19 hours ago [-]
I believe that -R is the safe works-as-expected-everywhere option.
pasc1878 19 hours ago [-]
Use rsync instead
5555watch 19 hours ago [-]
In my minimal attempts to use rsync, I always find examples where they always use a ton of flags alongside the locations. I'm not gonna learn those flags if cp can do it intuitively and with minimal extra commands. Maybe it's just me.
CoastalCoder 18 hours ago [-]
Not just you.

Also, I always have this vague fear that I'll rsync in the wrong direction, or accidentally blow away unrelated files in rsync's efforts to fully synchronize two directories (can't remember if this is a valid concern).

I'm sure these concerns would go away if I used it regularly, but I just don't. ‘cp' or ’scp’ almost always meet my needs.

Kinda like the way people are probably right that I should learn to use ’awk’, but I just can't muster the motivation.

groestl 18 hours ago [-]
Do it once, make it your muscle memory - it's really hard for me to learn things by heart, but even I could do it :), and then you can forget about scp as well
trucks-refinish 19 hours ago [-]
rsync unfortunately doesn't do relinking at all, so I can't use it as a generic replacement for cp.
groestl 18 hours ago [-]
Relinking?
rincebrain 18 hours ago [-]
I assume they typoed reflinking, a way of doing CoW-based copying of file contents.
groestl 18 hours ago [-]
I was under the impression it could do that, I think I build a snapshotting mechanism using this.
Flimm 18 hours ago [-]
rsync does not have the ability to copy a file using the filesystem's copy-on-write feature. This is unlike cp, which has the --reflink flag. Here's the bug report on GitHub which the developers closed as "won't fix for now":

https://github.com/RsyncProject/rsync/issues/119#issuecommen...

krn1p4n1c 18 hours ago [-]
tar cf - . | tar xf - -C <dest>
Rygian 18 hours ago [-]
with a sandwiched `| pv |` for fun stats
dspillett 18 hours ago [-]
And `| ssh <target> ` for a remote copy.

(or ssh <target> prepended rather than sandwiched, to copy from remote)

Rygian 17 hours ago [-]
At some point it starts very much looking like zfs send | pv | ssh <target> zfs receive
krn1p4n1c 16 hours ago [-]
Seriously. I do wish ZFS was everywhere.
krn1p4n1c 16 hours ago [-]
I usually sandwich zstd and base64 encode/decode in with the ssh pipe. Used when I need root permissions to pull the remote dirs.
dspillett 14 hours ago [-]
You shouldn't need to B64 encode for transfer - piping over SSH is binary safe. Verifying with 100Mbyte of random data:

    user@host:/tmp$ cat rnd.file | sha256sum
    71d3392be59210c517ab889fca715a46dee54f6326a9d901db0addd351607cb6  -
    user@host:/tmp$ cat rnd.file | ssh user@otherhost sha256sum
    71d3392be59210c517ab889fca715a46dee54f6326a9d901db0addd351607cb6  -
    user@host:/tmp$ cat rnd.file | zstd -z | ssh user@otherhost "zstd -d | sha256sum"
    71d3392be59210c517ab889fca715a46dee54f6326a9d901db0addd351607cb6  -
When using zstd (or anything else) make sure you don't have something in your .sss/config that would make ssh use a compression as you'll waste a bit of CPU to send a little more data as a less efficient compression method is applied on top. Though TBH I think that unless I'm on a very slow link, if I'm sending something big enough to need compression it is probably in a pre-compressed or otherwise uncompressable format anyway (video, photos, …) so zstd does little, the one exception I can think of being if I'm throwing an unencrypted VM image from place to place.
here_to_learn 20 hours ago [-]
[dead]
Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact
Rendered at 07:04:35 GMT+0000 (Coordinated Universal Time) with Vercel.