Skip to content

/flags/coreutils/cp-a-archive

cp -a: copy a directory and preserve timestamps, permissions and links

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · ls (GNU coreutils) 8.32updated
tool
GNU coreutils
command
cp
flag
-a, --archive
default
off (copies get new timestamps; directories need -r)

cp -a SOURCE DEST copies files and whole directory trees while keeping their metadata: modification times, permission bits, ownership (when you are root), symbolic links as links, hard links between copied files, and extended attributes. In GNU cp it is shorthand for -dR --preserve=all. Use it for backups, moving a data directory to a new disk, or any copy that must look identical to the original. A plain cp refuses directories (see cp: -r not specified; omitting directory) and stamps every copy with the current time.

Plain cp vs cp -a

bash
mkdir -p src/sub
echo hello > src/sub/notes.txt
touch -d '2020-01-02 03:04:05 UTC' src/sub/notes.txt
cp src/sub/notes.txt plain.txt
cp -a src/sub/notes.txt archived.txt
for f in plain.txt archived.txt; do
  if [ "$f" -nt src/sub/notes.txt ]; then echo "$f: new timestamp"; else echo "$f: $(date -u -r "$f" '+%F %T')"; fi
done
cp src copy-plain; echo "exit: $?"
cp -a src copy-a; find copy-a | sort

Output

plain.txt: new timestamp
archived.txt: 2020-01-02 03:04:05
cp: -r not specified; omitting directory 'src'
exit: 1
copy-a
copy-a/sub
copy-a/sub/notes.txt

Plain cp gives the file the time of the copy and refuses the directory; cp -a keeps the 2020 timestamp and copies the tree recursively.

What -a turns on

OptionMeaning
-a, --archiveSame as -dR --preserve=all
-R, -r, --recursiveCopy directories recursively
-dCopy symbolic links as links (--no-dereference --preserve=links)
-pSame as --preserve=mode,ownership,timestamps
--preserve=allAlso SELinux context and xattr; failures to keep those are not fatal
-u, --updateCopy only when the source is newer than the destination
-n, --no-clobberDo not overwrite existing files
-T, --no-target-directoryTreat DEST as the target itself, never as a directory to copy into

On macOS and the BSDs cp -a exists too and is equivalent to -RpP: recursive, preserve attributes, do not follow links. It is not in POSIX, which defines only -R and -p, so very old or minimal systems may lack it.

The existing-destination pitfall

cp -a src dest behaves differently depending on whether dest already exists:

bash
mkdir -p src
echo one > src/a.txt
cp -a src dest
cp -a src dest
find dest | sort
echo '--- contents only'
cp -a src/. dest2
find dest2 | sort

Output

dest
dest/a.txt
dest/src
dest/src/a.txt
--- contents only
dest2
dest2/a.txt

The second run copied src into dest, producing dest/src. Writing src/. copies the contents, so the command gives the same result every time. rsync -a has the same distinction through its trailing slash rule.

Platform notes

  • In Git Bash on Windows, permission bits are emulated, so -a mostly preserves timestamps; ownership is meaningless there, and symbolic links are copied as regular files unless native symlinks are enabled.
  • Preserving ownership needs root. As a normal user cp -a gives the copies your user and group.
  • cp -a shows no progress and restarts from zero if interrupted. For large or remote copies, rsync -a can resume and skip unchanged files.
  • Combine with -v to list each copied path, or -n to avoid overwriting files that are already in the destination.

FAQ

What is the difference between cp -a and cp -r?

cp -r copies the tree, but the copies get the current time and your default ownership and mode. cp -a is -dR --preserve=all: it also keeps timestamps, mode, ownership when allowed, symbolic links as links, hard links and extended attributes.

Why does cp -a src dest create dest/src?

When dest already exists as a directory, cp copies src into it. On the first run dest does not exist and becomes the copy; on the second run you get dest/src. Use cp -a src/. dest to copy the contents, or GNU cp -T to treat dest as the target itself.

Does cp -a keep the owner of the files?

Only when you are allowed to set it, which in practice means running as root. As a normal user the copies belong to you and cp -a does not fail because of it.

Sources