9.3 cp: Copying Files and Directories with -r, -p, -a
Right, cp. It’s the command you’ll use more than you’ll ever admit, and the one that will cause you more silent, screaming panic than any other when you get it wrong. It looks simple: cp [source] [destination]. And for a single file, it is. But the moment you need to copy a directory, you hit the first of many walls. Let’s get past them.
The Non-Negotiable -r (or -R)
Try to copy a directory without any flags. Go on, I’ll wait.
$ cp my_important_project my_backup
cp: -r not specified; omitting directory 'my_important_project'
See? The system is basically saying, “Look, I’m not a mind reader. That thing is a container, not a blob of text. If you want me to dive in there, grab everything inside it, including other containers, and replicate the whole mess, you need to explicitly tell me to be recursive.” This is your first and most important lesson: cp is cautious by default. It refuses to assume you want the monumental task of copying a directory tree.
The -r flag (or its uppercase identical twin -R) is your key. There is no functional difference between them; it’s just one of those charming bits of historical inconsistency that make Unix so… special.
# This is the way.
$ cp -r my_important_project my_backup
Now you’ll get a perfect (well, almost perfect, keep reading) copy of my_important_project inside my_backup.
Why -p is Probably What You Actually Want
So you’ve recursively copied your directory. Great! Now go check the permissions and timestamps on the new files.
$ ls -la my_important_project/critical_script.sh
-rwx------ 1 alex alex 1528 Jan 15 10:23 critical_script.sh
$ ls -la my_backup/critical_script.sh
-rw-r--r-- 1 root root 1528 Jan 16 14:51 critical_script.sh
Oh. Well, that’s ruined. The original was executable only by you (rwx------), but the copy is a wimpy read-only file owned by root. The timestamp is also now just the time you copied it. This is cp’s default behavior: it creates new files at the destination, which means they get your current umask, your current ownership, and the current time.
For a true backup, this is useless. You want the copy to be identical, metadata and all. This is where -p (preserve) comes in. It saves the original ownership, permissions, and timestamps.
# This is better. Much better.
$ cp -rp my_important_project my_backup
Fun fact: -p doesn’t preserve ownership by default if you’re a mere mortal user (only root can change a file’s owner to someone else). But it will try its best with everything else.
-a: The “Just Do Everything Right” Flag
You’re thinking, “So I need -r for recursion and -p for preservation. That’s two flags. I’m a busy person!” The designers felt your pain and created -a (archive). This flag is a super-set. It’s equivalent to -rp plus a bunch of other less-frequently-used preservation flags (like preserving context and links). In 99.9% of cases, -a is what you should use for any serious copy operation. It’s the “no, really, make an exact duplicate” button.
# The professional's choice. Do this.
$ cp -a my_important_project my_backup
The Quirks and The Catastrophes
Here’s where I stop you before you accidentally delete your entire home directory. cp’s behavior changes dangerously based on whether the destination exists.
- If the destination DOES NOT exist: You’re golden.
cp -a source destinationwill createdestinationas a copy ofsource. - If the destination IS AN EXISTING DIRECTORY: It copies the contents of
sourceintodestination. This is usually what you want. - If the destination IS AN EXISTING FILE: It will overwrite that file without so much as a courtesy whisper. This is how people cry.
Always, always use the -i (interactive) flag if you’re even 1% unsure. It’ll ask before clobbering anything. Make it a habit.
# Safety first, kids.
$ cp -ai source_directory destination_directory
And a final, crucial note: the trailing slash matters. Well, it doesn’t, but it changes how you think about the command. cp -a source/ dest is exactly the same as cp -a source dest. The shell handles the slash. But visually, source/ screams “I am copying the contents of source” while source implies “I am copying the thing called source.” The result is identical, but for your own sanity, be consistent. I always use the slash to mentally reinforce that I’m copying contents.