| | |

LFCA 15 ๐Ÿง Copying Files and Directories โ€” cp

cp copies files and directories. It reads the source, writes a new copy at the destination, and leaves the original untouched. It’s one of the commands you’ll use most often โ€” duplicating configs before editing, backing up files, moving data into a project directory, populating a template. On the surface it’s simple: cp SOURCE DEST. Underneath there are nuances โ€” how it handles directories, symlinks, permissions, timestamps, existing files, and the difference between copying a file into a directory versus onto a name. The LFCA exam expects you to know cp cold.

Key point: cp copies โ€” it doesn’t move. The source stays. The destination is a new file or directory with the same content. For files, cp SOURCE DEST writes a copy. For directories, you need -r (recursive). The trailing slash on a destination directory matters: cp file dir/ copies into the directory; cp file dir overwrites the file named dir if it exists. Get the destination semantics right and cp is predictable; get them wrong and you’ll either overwrite the wrong thing or fail with a confusing error.


What cp does

cp reads the source and writes a new copy at the destination. The original is unchanged.

$ echo "hello" > original.txt
$ cp original.txt copy.txt
$ cat original.txt
hello
$ cat copy.txt
hello

Both files exist with the same content. The original is untouched.

What cp copies:

  • File contents
  • Permissions (usually, depending on flags)
  • Timestamps (only with -p)
  • Ownership (only with -p and root)
  • Extended attributes (with -a or specific flags)

What cp doesn’t do:

  • Doesn’t move the original โ€” that’s mv
  • Doesn’t delete the source
  • Doesn’t create parent directories by default
  • Doesn’t follow or not follow symlinks the way you might expect without flags

The basic forms:

FormMeaning
cp file1 file2Copy file1 to file2
cp file1 dir/Copy file1 into dir/
cp file1 file2 dir/Copy multiple files into dir/
cp -r dir1 dir2Copy dir1 to dir2 (recursive)
cp -r dir1/ dir2/Copy contents of dir1 into dir2/

Destination semantics: The most important thing to understand about cp.

  • If the destination is a directory, the source is copied into it (with the same basename)
  • If the destination is a name that doesn’t exist, a new file or directory is created with that name
  • If the destination is an existing file, cp overwrites it (unless -i or -n)
$ cp file.txt /tmp/           # copies to /tmp/file.txt
$ cp file.txt newname.txt     # copies to ./newname.txt
$ cp file.txt existing.txt    # overwrites existing.txt

Why the distinction matters: Most cp mistakes are destination mistakes โ€” copying into the wrong place, overwriting a file you wanted to keep, or failing because the destination didn’t exist. Understanding the three cases prevents all of them.

Why cp and mv are separate: cp preserves the original; mv moves it. They’re different operations with different costs (copying is I/O-heavy; moving is a rename). Keeping them separate matches the Unix philosophy โ€” one command, one purpose.


Copying files

The simplest case: copying one file to another.

Copy to a new name in the same directory:

$ cp report.txt report-backup.txt
$ ls
report-backup.txt  report.txt

Copy to a different directory:

$ cp report.txt /tmp/
$ ls /tmp/report.txt
/tmp/report.txt

When the destination is a directory, the file keeps its name.

Copy to a different directory with a new name:

$ cp report.txt /tmp/summary.txt
$ ls /tmp/summary.txt
/tmp/summary.txt

Copy multiple files to a directory:

$ cp file1.txt file2.txt file3.txt /tmp/
$ ls /tmp/file*.txt
/tmp/file1.txt  /tmp/file2.txt  /tmp/file3.txt

The last argument must be a directory. Each source is copied into it.

Copy with a wildcard:

$ cp *.txt /tmp/

The shell expands *.txt into multiple filenames; cp copies them all into /tmp/.

Overwriting an existing file:

$ echo "original" > dest.txt
$ cp source.txt dest.txt
$ cat dest.txt
(from source.txt)

By default, cp overwrites silently. Use -i to prompt or -n to skip.

What cp does to permissions: By default, cp creates the destination with the source’s permissions modified by the umask. To preserve exactly, use -p.

$ ls -l source.txt
-rwxr-xr-x 1 alice alice 0 Sep 22 10:30 source.txt

$ cp source.txt dest.txt
$ ls -l dest.txt
-rwxr-xr-x 1 alice alice 0 Sep 22 10:30 dest.txt

In this case permissions match because the umask doesn’t strip anything from the source. If the source has unusual permissions, cp -p is needed to preserve them exactly.

Why the umask applies: New files inherit the umask. Even when copying, the destination is a new file โ€” the umask masks the mode. -p overrides this.

Why “copy to a directory” is the common case: You rarely copy a file to another name in the same directory. You usually copy it elsewhere โ€” a backup directory, a temp directory, another project. The destination-is-a-directory form handles that cleanly.


cp -i, -n, -u โ€” handling existing files

By default, cp overwrites existing files silently. Three flags change this.

-i โ€” interactive:

$ cp -i source.txt dest.txt
cp: overwrite 'dest.txt'? y

Prompts before overwriting. The answer must start with y or Y to proceed.

-n โ€” no clobber:

$ cp -n source.txt dest.txt
$ echo $?
0

Doesn’t overwrite. If the destination exists, cp silently skips it.

-u โ€” update only:

$ cp -u source.txt dest.txt

Copies only if the source is newer than the destination, or if the destination doesn’t exist. Useful for sync-like behavior.

When to use each:

FlagUse case
-iInteractive โ€” you want to confirm each overwrite
-nScripting โ€” never overwrite
-uSync โ€” only copy newer files

The alias trap: Many systems alias cp to cp -i:

$ alias cp
alias cp='cp -i'

In interactive shells, cp prompts. In scripts, aliases don’t apply โ€” cp overwrites silently. That’s a common source of surprise: the same command behaves differently in a script.

To bypass an alias: \cp or command cp or the full path /bin/cp.

Why -i is often aliased: Accidental overwrites are a common mistake. Aliasing cp to cp -i protects against them. But it only affects interactive shells โ€” scripts see the plain cp.

Why -n is safer in scripts: A script shouldn’t prompt โ€” there’s no one to answer. -n makes the behavior deterministic: never overwrite. If the script needs to overwrite, it shouldn’t use -n.

Why -u exists: It’s a poor man’s sync. Copy only what’s changed. For real sync, use rsync, but cp -u covers the simple case.

Why “clobber” is the term: “Clobber” means to overwrite destructively. -n (no clobber) is the standard Unix term for “don’t overwrite.” The wording is old but consistent across tools.


Copying directories with -r

cp needs -r (or -R, --recursive) to copy a directory.

$ cp -r source-dir dest-dir

Without -r:

$ cp source-dir dest-dir
cp: -r not specified; omitting directory 'source-dir'

cp refuses to copy a directory unless told to recurse.

What -r does: Copies the directory and everything inside it โ€” subdirectories, files, symlinks โ€” recursively.

The destination rules for directories:

If the destination doesn’t exist:

$ cp -r source dest
# Creates dest/ with source's contents
# dest/source equivalent โ€” no, dest IS the copy

The result: dest/ contains everything source/ had. source/ still exists.

If the destination exists as a directory:

$ cp -r source dest/
# Creates dest/source/ with source's contents

The source directory is copied inside dest/. Result: dest/source/.

This is the subtle part. The presence of the destination determines the behavior:

  • cp -r source dest (dest doesn’t exist) โ†’ dest becomes the copy of source
  • cp -r source dest (dest exists) โ†’ source is copied into dest, producing dest/source
  • cp -r source/. dest โ†’ copies the contents of source into dest, not the directory itself

Copying contents, not the directory:

$ mkdir dest
$ cp -r source/. dest/
# dest/ now contains everything inside source/
# no dest/source subdirectory

The /. at the end of the source means “the contents of this directory.” That’s the standard idiom for copying contents into an existing directory without nesting.

Examples:

$ mkdir -p a/b/c
$ touch a/b/c/file.txt

$ cp -r a copy1
$ find copy1
copy1
copy1/b
copy1/b/c
copy1/b/c/file.txt

$ mkdir existing
$ cp -r a existing
$ find existing
existing
existing/a
existing/a/b
existing/a/b/c
existing/a/b/c/file.txt

First case: dest was new, so it becomes a copy of source. Second: dest existed, so source was nested inside.

Why the difference: cp follows the same rule as with files. If the destination is a directory, the source is copied into it. If the destination is a name, the copy becomes that name. Directories aren’t special โ€” the rule is uniform.

Why the “contents” idiom exists: Often you want to copy what’s inside a directory into another directory, not nest one inside the other. cp -r source/. dest/ says “all of source’s entries, into dest.” The /. is how you express “the contents” rather than “the directory.”


Preserving attributes with -p and -a

By default, cp creates new files with new metadata. -p preserves the important attributes; -a preserves everything.

-p โ€” preserve:

$ cp -p source.txt dest.txt

Preserves:

  • Permissions (mode)
  • Ownership (if permitted โ€” root only)
  • Timestamps (atime, mtime)
  • Extended attributes (on some systems)

What -p doesn’t preserve:

  • The inode number (always new)
  • Hard links (each is copied as a separate file)
  • SELinux contexts (in some configurations)

-a โ€” archive:

$ cp -a source dest

-a is equivalent to -dR --preserve=all. It preserves everything -p does, plus recurses and preserves symlinks as symlinks.

What -a preserves:

  • Permissions, ownership, timestamps
  • Symlinks as symlinks (not copied as regular files)
  • Hard links (preserved as hard links within the copy)
  • Extended attributes, ACLs, SELinux contexts

When to use which:

TaskFlag
Copy config, keep perms-p
Backup a directory-a
Copy a project tree-a
Copy a file with new timestamps(none)

Example of timestamp preservation:

$ ls -l source.txt
-rw-r--r-- 1 alice alice 123 Jan 15 09:00 source.txt

$ cp source.txt dest.txt
$ ls -l dest.txt
-rw-r--r-- 1 alice alice 123 Sep 22 10:30 dest.txt
# (new timestamp)

$ cp -p source.txt dest2.txt
$ ls -l dest2.txt
-rw-r--r-- 1 alice alice 123 Jan 15 09:00 dest2.txt
# (original timestamp preserved)

Symlink handling: By default, cp follows symlinks โ€” copying the target’s content. -P or -a preserves them as symlinks.

$ ln -s target.txt link.txt

$ cp link.txt copy.txt
# copy.txt is a regular file with target.txt's content

$ cp -P link.txt copy2.txt
# copy2.txt is a symlink pointing to target.txt

$ cp -a link.txt copy3.txt
# copy3.txt is a symlink (same as -P)

Why -a is called “archive”: It’s designed for backups โ€” copy a tree with everything preserved exactly. The name comes from tar-style archiving: keep all attributes.

Why ownership preservation needs root: Only root can change file ownership. A regular user’s cp -p preserves permissions and timestamps but not owner (since the new file will be owned by the copying user). Root can preserve ownership because root can chown.


Copying symlinks

Symlinks introduce a choice: copy the link itself, or copy the target?

By default โ€” follow (copy the target):

$ ln -s /etc/hosts mylink
$ cp mylink mycopy
$ ls -l mycopy
-rw-r--r-- 1 alice alice 234 Sep 22 10:30 mycopy

mycopy is a regular file with /etc/hosts‘s content. The symlink wasn’t copied โ€” its target was.

With -P or -d โ€” no dereference:

$ cp -P mylink mylinkcopy
$ ls -l mylinkcopy
lrwxrwxrwx 1 alice alice 10 Sep 22 10:30 mylinkcopy -> /etc/hosts

mylinkcopy is a symlink pointing to /etc/hosts.

With -a or -dR โ€” same as -P:

-a implies -P and -d, so symlinks are preserved.

With -L โ€” force follow:

$ cp -L mylink copy

-L forces following even if -P was implied by another flag.

The flags:

FlagBehavior
(default)Follow symlinks โ€” copy the target
-PNever follow โ€” copy the symlink
-LAlways follow โ€” copy the target
-aImplies -P โ€” preserve symlinks
-dSame as -P --no-dereference --preserve=links

When each matters:

  • Default โ€” you want the content, and you don’t care that the original was a symlink
  • -P โ€” you want an exact replica of the tree, including symlinks
  • -L โ€” you want to resolve all symlinks into regular files

Why -a preserves symlinks: It’s for backups. A backup that dereferences symlinks loses information โ€” the restored tree wouldn’t match the original. -a keeps symlinks as symlinks.

Why -P in a project copy: A project might have symlinks (e.g., node_modules/.bin/*). Copying with -P preserves the structure. Copying with the default would dereference them, creating separate copies of the targets โ€” often not what you want.

Why the default is “follow”: Most people copying a file want its contents, not a pointer. The symlink is usually an implementation detail. So cp follows by default. When you need the symlink itself, use -P or -a.


A full example

Using cp for common tasks.

# ============================================
# PART 1: BACKUP A FILE
# ============================================

cd ~
echo "important config" > app.conf
cp app.conf app.conf.bak
ls
# app.conf  app.conf.bak

# ============================================
# PART 2: COPY TO A DIRECTORY
# ============================================

mkdir backups
cp app.conf backups/
ls backups/
# app.conf

# ============================================
# PART 3: COPY WITH A NEW NAME
# ============================================

cp app.conf backups/app.conf.old
ls backups/
# app.conf  app.conf.old

# ============================================
# PART 4: INTERACTIVE OVERWRITE
# ============================================

cp -i app.conf backups/app.conf
# cp: overwrite 'backups/app.conf'? y

# ============================================
# PART 5: NO-CLOBBER
# ============================================

cp -n app.conf backups/app.conf
# (silent, no overwrite)

echo $?
# 0

# ============================================
# PART 6: COPY A DIRECTORY
# ============================================

mkdir -p project/src
touch project/src/main.js
touch project/README.md

cp -r project project-copy
find project-copy
# project-copy
# project-copy/README.md
# project-copy/src
# project-copy/src/main.js

# ============================================
# PART 7: COPY INTO AN EXISTING DIRECTORY
# ============================================

mkdir dest
cp -r project dest/
find dest
# dest
# dest/project
# dest/project/README.md
# dest/project/src
# dest/project/src/main.js

# ============================================
# PART 8: COPY CONTENTS ONLY
# ============================================

mkdir dest2
cp -r project/. dest2/
find dest2
# dest2
# dest2/README.md
# dest2/src
# dest2/src/main.js

# ============================================
# PART 9: PRESERVE TIMESTAMPS
# ============================================

ls -l app.conf
# -rw-r--r-- ... app.conf

sleep 2
cp -p app.conf app-preserved.conf
ls -l app-preserved.conf
# (timestamp same as app.conf)

# ============================================
# PART 10: ARCHIVE COPY
# ============================================

cp -a project project-archive
find project-archive -type f
# project-archive/README.md
# project-archive/src/main.js

# ============================================
# PART 11: COPY SYMLINKS
# ============================================

ln -s app.conf config-link

cp config-link copied-link
ls -l copied-link
# -rw-r--r-- ... copied-link (regular file)

cp -P config-link preserved-link
ls -l preserved-link
# lrwxrwxrwx ... preserved-link -> app.conf

# ============================================
# PART 12: COPY MULTIPLE FILES
# ============================================

touch file1.txt file2.txt file3.txt
mkdir txts
cp *.txt txts/
ls txts/
# file1.txt  file2.txt  file3.txt

# ============================================
# PART 13: WILDCARD WITH PATTERN
# ============================================

mkdir logs
touch logs/{access,error,debug}.log
cp logs/*.log logs-backup/ 2>/dev/null || true
mkdir logs-backup
cp logs/*.log logs-backup/
ls logs-backup/
# access.log  debug.log  error.log

Each part demonstrates a different cp use. Together they cover the practical range.

Why this session: It covers backup, directory copying, contents-only copying, timestamp preservation, symlink handling, and wildcards. These are the real tasks cp does. Once they’re familiar, cp is predictable.


Complete Example Session

# ============================================
# PART 1: BASIC FILE COPY
# ============================================

echo "content" > original.txt
cp original.txt copy.txt
cat copy.txt
# [ content ]

ls
# [ copy.txt  original.txt ]

# ============================================
# PART 2: COPY TO A DIRECTORY
# ============================================

mkdir archive
cp original.txt archive/
ls archive/
# [ original.txt ]

# ============================================
# PART 3: COPY WITH NEW NAME
# ============================================

cp original.txt archive/newname.txt
ls archive/
# [ newname.txt  original.txt ]

# ============================================
# PART 4: MULTIPLE SOURCES
# ============================================

touch a.txt b.txt c.txt
mkdir all
cp a.txt b.txt c.txt all/
ls all/
# [ a.txt  b.txt  c.txt ]

# ============================================
# PART 5: WILDCARD
# ============================================

touch more.txt
cp *.txt all/
# cp: target 'all' is not a directory? No โ€” it is
# Actually copies all .txt files

ls all/
# [ a.txt  b.txt  c.txt  more.txt  original.txt ]

# ============================================
# PART 6: OVERWRITE DEFAULT
# ============================================

echo "old" > dest.txt
echo "new" > source.txt
cp source.txt dest.txt
cat dest.txt
# [ new ]

# ============================================
# PART 7: -i INTERACTIVE
# ============================================

cp -i source.txt dest.txt
# [ cp: overwrite 'dest.txt'? ]

# Answer n
# cat dest.txt still "new"

# ============================================
# PART 8: -n NO CLOBBER
# ============================================

cp -n source.txt dest.txt
# No prompt, no overwrite
cat dest.txt
# [ new ]

# ============================================
# PART 9: -u UPDATE
# ============================================

# Copy only if source newer
cp -u source.txt dest.txt
cat dest.txt
# [ new ]

# ============================================
# PART 10: RECURSIVE COPY
# ============================================

mkdir -p tree/sub
touch tree/file.txt tree/sub/deep.txt

cp -r tree tree-copy
find tree-copy
# [ tree-copy ]
# [ tree-copy/file.txt ]
# [ tree-copy/sub ]
# [ tree-copy/sub/deep.txt ]

# ============================================
# PART 11: NESTED VS CONTENTS
# ============================================

mkdir existing
cp -r tree existing/
ls existing/
# [ tree ]

mkdir target
cp -r tree/. target/
ls target/
# [ file.txt  sub ]

# ============================================
# PART 12: PRESERVE ATTRIBUTES
# ============================================

ls -l original.txt
# [ -rw-r--r-- 1 alice alice 8 Sep 22 10:30 original.txt ]

sleep 2

cp original.txt no-preserve.txt
ls -l no-preserve.txt
# [ -rw-r--r-- 1 alice alice 8 Sep 22 10:32 no-preserve.txt ]

cp -p original.txt preserved.txt
ls -l preserved.txt
# [ -rw-r--r-- 1 alice alice 8 Sep 22 10:30 preserved.txt ]

# ============================================
# PART 13: ARCHIVE COPY
# ============================================

cp -a tree tree-archive
diff -r tree tree-archive
# (no output โ€” identical)

# ============================================
# PART 14: SYMLINK HANDLING
# ============================================

ln -s original.txt link.txt
ls -l link.txt
# [ lrwxrwxrwx ... link.txt -> original.txt ]

cp link.txt followed.txt
ls -l followed.txt
# [ -rw-r--r-- ... followed.txt ]
file followed.txt
# [ followed.txt: ASCII text ]

cp -P link.txt preserved-link.txt
ls -l preserved-link.txt
# [ lrwxrwxrwx ... preserved-link.txt -> original.txt ]

# ============================================
# PART 15: PRACTICAL BACKUP
# ============================================

mkdir -p ~/backups/$(date +%Y-%m-%d)
cp -a /etc/nginx ~/backups/$(date +%Y-%m-%d)/ 2>/dev/null || echo "nginx not found"

# ============================================
# PART 16: PROJECT TEMPLATE
# ============================================

mkdir -p template/{src,docs,tests}
touch template/README.md

cp -r template newproject
cd newproject
ls
# [ README.md  docs  src  tests ]

Every part exercises a cp feature. Together they cover the practical range.


Quick Reference

cp Syntax

FormMeaning
cp SRC DESTCopy file to file
cp SRC DIR/Copy file into directory
cp SRC1 SRC2 DIR/Multiple sources into directory
cp -r DIR1 DIR2Copy directory recursively
cp -r DIR/. DIR2/Copy contents into directory

Common Flags

FlagEffect
-r / -RRecursive
-aArchive โ€” preserve all, recursive
-pPreserve mode, ownership, timestamps
-iInteractive โ€” prompt before overwrite
-nNo clobber โ€” don’t overwrite
-uUpdate โ€” copy only if newer
-vVerbose
-fForce โ€” remove and retry if needed
-lHard link instead of copy
-sSymlink instead of copy
-PNo dereference โ€” copy symlinks
-LAlways dereference โ€” follow symlinks
-dSame as -P --preserve=links
-t DIRTarget directory first

Flags That Imply Others

FlagEquivalent to
-a-dR --preserve=all
-d-P --preserve=links
-RSame as -r
-HFollow command-line symlinks only

Destination Rules for Files

DestinationResult
Doesn’t existCreated with source’s content
Existing fileOverwritten (unless -i, -n)
DirectoryCopied inside with same basename

Destination Rules for Directories

DestinationResult
Doesn’t existNew dir with source’s contents
Existing dirSource nested inside
DIR/. sourceContents copied into destination

Symlink Behavior

FlagBehavior
(default)Follow โ€” copy target
-PNo follow โ€” copy symlink
-LAlways follow
-aImplies -P

Preserve Options

OptionEffect
-pPreserve mode, ownership, timestamps
-aPreserve everything
--preserve=modeMode only
--preserve=timestampsTimestamps only
--preserve=allEverything

Error Messages

MessageCause
omitting directoryUsed cp without -r on a directory
No such file or directorySource doesn’t exist
Permission deniedNo read/write permission
same fileSource and destination are the same
target is not a directoryMultiple sources, last isn’t a directory
cannot overwrite non-directory with directoryType mismatch

Common Patterns

TaskCommand
Backup filecp file file.bak
Copy to directorycp file /path/
Copy directorycp -r dir1 dir2
Copy contentscp -r dir1/. dir2/
Archive copycp -a src dst
Interactivecp -i src dst
No overwritecp -n src dst
Update onlycp -u src dst
Preserve metacp -p src dst
Multiple filescp file1 file2 dir/

When to Use Which Flag

SituationFlag
Backup everything-a
One file, keep attrs-p
Script safety-n
Confirm each-i
Sync-like-u
Directory-r
Preserve symlinks-a or -P
Verbose-v

Interaction with umask

ActionEffect
Default copyumask applies
-pumask ignored, source’s mode kept
-aumask ignored

Verification

CommandShows
diff file1 file2Differences
diff -r dir1 dir2Directory diffs
cmp file1 file2Byte comparison
ls -lFile details
md5sum fileHash for equality

Best Practices

โœ… Do This:

# Use -i for interactive safety
cp -i source dest                                       # โœ…

# Use -n in scripts to avoid overwrites
cp -n source dest                                       # โœ…

# Use -r for directories
cp -r src-dir dest-dir                                  # โœ…

# Preserve timestamps for backups
cp -p important.conf important.conf.bak                 # โœ…

# Use -a for full backups
cp -a project/ backup/                                  # โœ…

# Copy contents, not the directory
cp -r source/. destination/                             # โœ…

# Verify after copying
diff -r source/ destination/                            # โœ…

# Use -v in scripts that log
cp -v source dest                                       # โœ…

# Quote paths with spaces
cp "My File.txt" "My File Copy.txt"                     # โœ…

# Use $(date) for timestamped backups
cp app.conf app.conf.$(date +%Y%m%d)                    # โœ…

โŒ Don’t Do This:

# Don't forget -r for directories
cp source-dir dest                                      # โŒ

# Don't overwrite silently in scripts
cp source dest  # overwrites without warning           # โš ๏ธ

# Don't assume the destination is what you think
cp file.txt /tmp  # is /tmp a dir? yes                   # โœ…
# But:
cp file.txt /tmp  # if /tmp is a file โ†’ copies over it  # โš ๏ธ

# Don't rely on umask for protection
cp secret.txt public/  # umask may not be enough        # โš ๏ธ

# Don't use cp for symlinks without -P
cp -r tree copy  # loses symlinks                        # โš ๏ธ

# Don't create content with cp
cp empty.txt file  # both empty                          # โš ๏ธ

# Don't use cp to move large files
cp bigfile bigcopy && rm bigfile  # use mv instead       # โš ๏ธ

# Don't skip the trailing slash meaning
cp -r src dest/   # nests source inside dest             # โš ๏ธ
cp -r src/. dest/ # contents only                        # โœ…

# Don't ignore errors
cp -r dir dest 2>/dev/null  # silent failure             # โš ๏ธ

# Don't copy to a path without permissions
cp file /root/  # permission denied for non-root         # โš ๏ธ

Common Pitfalls

PitfallProblemSolution
Missing -rDirectory copy failsAdd -r
cp dir dest nestsUnexpected structureUse dir/.
Overwrites silentlyLost fileUse -i or -n
Alias not in scriptDifferent behaviorUse full path
cp -p as non-rootOwnership not preservedExpected
cp follows symlinksRegular file createdUse -P
Umask modifies permsDifferent from sourceUse -p
Multiple sourcesLast isn’t dirFix order
Source is dir, no -rErrorAdd -r
Destination same as sourcesame file errorDifferent name

Real-World Examples

1. Backup a file

cp config.ini config.ini.bak

2. Backup with date

cp config.ini config.ini.$(date +%Y%m%d)

3. Copy to directory

cp report.pdf ~/Documents/

4. Copy with new name

cp original.txt renamed.txt

5. Copy multiple files

cp *.log /var/log/archive/

6. Interactive overwrite

cp -i file1.txt file2.txt

7. No-overwrite copy

cp -n source.txt dest.txt

8. Update-only copy

cp -u /src/* /dest/

9. Copy a directory

cp -r projects projects-backup

10. Copy contents

cp -r template/. myproject/

11. Preserve timestamps

cp -p original.txt preserved.txt

12. Archive copy

cp -a /etc/nginx /backups/nginx-$(date +%F)

13. Copy with symlinks preserved

cp -a node_modules /tmp/nm-backup

14. Verbose copy

cp -rv source-dir dest-dir

15. Force overwrite

cp -f source dest

16. Hard link instead

cp -l original hardlink

17. Symlink instead

cp -s /path/to/file symlink-name

18. Copy a project skeleton

cp -r ~/templates/webapp ./newapp

19. Copy dotfiles

cp -a ~/.config/.* /backup/config/

20. Verify a copy

diff -r source-dir dest-dir

Visual: cp Basics

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  source.txt                                  โ”‚
โ”‚  โ”€ content: "hello"                          โ”‚
โ”‚  โ”€ permissions: rw-r--r--                    โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                  โ”‚
                  โ”‚  cp source.txt dest.txt
                  โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  source.txt (unchanged)                      โ”‚
โ”‚  dest.txt (new, identical content)           โ”‚
โ”‚                                              โ”‚
โ”‚  Both exist now                              โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Destination Semantics

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  cp file.txt newname.txt                     โ”‚
โ”‚                                              โ”‚
โ”‚  โ†’ file.txt copied to ./newname.txt          โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  cp file.txt /tmp/                           โ”‚
โ”‚                                              โ”‚
โ”‚  โ†’ file.txt copied to /tmp/file.txt          โ”‚
โ”‚  โ†’ destination is a directory                โ”‚
โ”‚  โ†’ source basename is kept                   โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  cp file.txt existing-file.txt               โ”‚
โ”‚                                              โ”‚
โ”‚  โ†’ existing-file.txt overwritten             โ”‚
โ”‚  โ†’ unless -i or -n                           โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Directory Copy Behavior

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Case 1: Destination doesn't exist           โ”‚
โ”‚                                              โ”‚
โ”‚  $ cp -r source dest                         โ”‚
โ”‚                                              โ”‚
โ”‚  source/ โ”€โ”€โ–บ becomes dest/                   โ”‚
โ”‚                                              โ”‚
โ”‚  dest/                                       โ”‚
โ”‚  โ”œโ”€โ”€ (source's contents)                     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Case 2: Destination exists as a directory   โ”‚
โ”‚                                              โ”‚
โ”‚  $ cp -r source existing/                    โ”‚
โ”‚                                              โ”‚
โ”‚  source/ โ”€โ”€โ–บ nested inside existing/         โ”‚
โ”‚                                              โ”‚
โ”‚  existing/                                   โ”‚
โ”‚  โ””โ”€โ”€ source/                                 โ”‚
โ”‚      โ”œโ”€โ”€ (source's contents)                 โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Case 3: Copy contents only                  โ”‚
โ”‚                                              โ”‚
โ”‚  $ cp -r source/. existing/                  โ”‚
โ”‚                                              โ”‚
โ”‚  source's contents โ†’ existing/               โ”‚
โ”‚                                              โ”‚
โ”‚  existing/                                   โ”‚
โ”‚  โ”œโ”€โ”€ (source's files)                        โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Preserve Attributes

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  $ cp source.txt dest.txt                    โ”‚
โ”‚                                              โ”‚
โ”‚  source.txt:                                 โ”‚
โ”‚    mode: 755                                 โ”‚
โ”‚    mtime: Jan 15 09:00                       โ”‚
โ”‚                                              โ”‚
โ”‚  dest.txt (default cp):                      โ”‚
โ”‚    mode: 755 (from umask? kept)              โ”‚
โ”‚    mtime: now โ† updated                      โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  $ cp -p source.txt dest.txt                 โ”‚
โ”‚                                              โ”‚
โ”‚  dest.txt:                                   โ”‚
โ”‚    mode: 755 (exact)                         โ”‚
โ”‚    mtime: Jan 15 09:00 (preserved)           โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  $ cp -a source-dir dest-dir                 โ”‚
โ”‚                                              โ”‚
โ”‚  All of:                                     โ”‚
โ”‚    permissions โœ…                            โ”‚
โ”‚    ownership (root) โœ…                       โ”‚
โ”‚    timestamps โœ…                             โ”‚
โ”‚    symlinks as symlinks โœ…                   โ”‚
โ”‚    hard links โœ…                             โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Symlink Behavior

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  source-dir/                                 โ”‚
โ”‚  โ”œโ”€โ”€ file.txt                                โ”‚
โ”‚  โ””โ”€โ”€ link.txt โ†’ file.txt                     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  cp -r source-dir dest                       โ”‚
โ”‚                                              โ”‚
โ”‚  dest/                                       โ”‚
โ”‚  โ”œโ”€โ”€ file.txt                                โ”‚
โ”‚  โ””โ”€โ”€ link.txt   โ† regular file (target copy) โ”‚
โ”‚                                              โ”‚
โ”‚  (default follows symlinks)                  โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  cp -a source-dir dest                       โ”‚
โ”‚                                              โ”‚
โ”‚  dest/                                       โ”‚
โ”‚  โ”œโ”€โ”€ file.txt                                โ”‚
โ”‚  โ””โ”€โ”€ link.txt โ†’ file.txt                     โ”‚
โ”‚                                              โ”‚
โ”‚  (symlink preserved)                         โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: -i vs -n vs -u

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Default: silent overwrite                   โ”‚
โ”‚                                              โ”‚
โ”‚  $ cp src dst                                โ”‚
โ”‚  (dst overwritten)                           โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  -i: interactive                             โ”‚
โ”‚                                              โ”‚
โ”‚  $ cp -i src dst                             โ”‚
โ”‚  cp: overwrite 'dst'? _                      โ”‚
โ”‚                                              โ”‚
โ”‚  y โ†’ overwrite                               โ”‚
โ”‚  n โ†’ skip                                    โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  -n: no clobber                              โ”‚
โ”‚                                              โ”‚
โ”‚  $ cp -n src dst                             โ”‚
โ”‚  (dst not overwritten)                       โ”‚
โ”‚                                              โ”‚
โ”‚  Silent skip โ€” no prompt                     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  -u: update only                             โ”‚
โ”‚                                              โ”‚
โ”‚  $ cp -u src dst                             โ”‚
โ”‚  โ”€ If src newer than dst โ†’ overwrite         โ”‚
โ”‚  โ”€ If dst newer or same โ†’ skip               โ”‚
โ”‚  โ”€ If dst missing โ†’ copy                     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Common Backup Workflow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Before editing a config:                    โ”‚
โ”‚                                              โ”‚
โ”‚  1. cp /etc/nginx/nginx.conf \               โ”‚
โ”‚        /etc/nginx/nginx.conf.bak             โ”‚
โ”‚                                              โ”‚
โ”‚  2. (edit /etc/nginx/nginx.conf)             โ”‚
โ”‚                                              โ”‚
โ”‚  3. If problems:                             โ”‚
โ”‚     cp /etc/nginx/nginx.conf.bak \           โ”‚
โ”‚        /etc/nginx/nginx.conf                 โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Before upgrading a directory:               โ”‚
โ”‚                                              โ”‚
โ”‚  1. cp -a project project-$(date +%F)        โ”‚
โ”‚                                              โ”‚
โ”‚  2. (upgrade project)                        โ”‚
โ”‚                                              โ”‚
โ”‚  3. If problems:                             โ”‚
โ”‚     rm -rf project                           โ”‚
โ”‚     mv project-$(date +%F) project           โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: cp vs mv

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  cp source dest                              โ”‚
โ”‚                                              โ”‚
โ”‚  source โ†’ still exists                       โ”‚
โ”‚  dest โ†’ new copy                             โ”‚
โ”‚                                              โ”‚
โ”‚  Reads + writes data                         โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  mv source dest                              โ”‚
โ”‚                                              โ”‚
โ”‚  source โ†’ gone                               โ”‚
โ”‚  dest โ†’ same inode (if same filesystem)      โ”‚
โ”‚                                              โ”‚
โ”‚  Renames โ€” fast if same fs                   โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Path Forms

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  cp /etc/hosts /tmp/hosts-copy               โ”‚
โ”‚       absolute    absolute                   โ”‚
โ”‚                                              โ”‚
โ”‚  cp hosts /tmp/                              โ”‚
โ”‚       relative    absolute                   โ”‚
โ”‚                                              โ”‚
โ”‚  cp ~/notes.txt .                            โ”‚
โ”‚       from home    to current                โ”‚
โ”‚                                              โ”‚
โ”‚  cp ../other/file.txt ./file.txt             โ”‚
โ”‚       from parent   to current               โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Decision Flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Copying a file?                             โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ””โ”€โ”€ cp SRC DEST                        โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Copying a directory?                        โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ””โ”€โ”€ cp -r SRC DEST                     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Want to preserve everything?                โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ””โ”€โ”€ cp -a SRC DEST                     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Worried about overwriting?                  โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ”œโ”€โ”€ Interactive โ”€โ”€โ–บ -i                 โ”‚
โ”‚       โ”œโ”€โ”€ Never โ”€โ”€โ–บ -n                       โ”‚
โ”‚       โ””โ”€โ”€ Only if newer โ”€โ”€โ–บ -u               โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Copying contents, not the directory?        โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ””โ”€โ”€ cp -r src/. dest/                  โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Preserve symlinks?                          โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ””โ”€โ”€ cp -a or cp -P                     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

CommandPurpose
cp SRC DESTCopy file to file
cp SRC DIR/Copy file into directory
cp -r DIR1 DIR2Copy directory
cp -r DIR/. DIR2/Copy contents only
cp -a SRC DESTArchive copy
cp -p SRC DESTPreserve attributes
cp -i SRC DESTInteractive overwrite
cp -n SRC DESTNever overwrite
cp -u SRC DESTCopy only if newer
cp -P SRC DESTCopy symlinks as symlinks

Key takeaways:

  • cp copies โ€” the source stays, the destination is new
  • Destination is a directory โ†’ source copied into it, keeping the basename
  • Destination is a name โ†’ the copy becomes that name; existing files are overwritten
  • -r is required for directories โ€” no exceptions
  • cp -r src dest nests differently depending on whether dest exists
  • cp -r src/. dest/ copies contents, not the directory itself
  • -i prompts before overwrite; -n never overwrites; -u copies only if newer
  • -p preserves permissions, ownership, and timestamps
  • -a is -p plus recursive plus symlink preservation โ€” the backup flag
  • Default behavior follows symlinks โ€” use -P or -a to preserve them
  • umask applies to new files unless -p or -a is used
  • Aliases only affect interactive shells โ€” scripts see plain cp
  • Verify with diff -r source dest

Remember: cp is the copy command โ€” source stays, destination is new. It’s simple for files, careful for directories, and full of subtle flags for edge cases. Know the destination semantics (into vs onto), use -r for directories, -a for backups, -i or -n to prevent overwrites, and -p when timestamps matter. Get those right and cp becomes one of the most reliable tools in your kit. Nearly every workflow starts by copying something โ€” a config for backup, a template for a new project, a file into a directory. That’s what cp is for.


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!