Daily Linux Command: cp

The cp (copy) command is used to copy files. The cp command can copy both text files and binary files, and it can also recursively copy directories.

✦•———-Basic Usage———-•✦

  • Copying Files

Copy the source file src.txt to the new file dest.txt

$ cp src.txt dest.txt

If the cp command produces no output, it indicates that the file was copied successfully.

  • Copying Files with Details

Using the -v option allows us to see the copying process.

$ cp -v src.txt dest.txt'src.txt' -> 'dest.txt'
  • ⚠️Warning: The cp command may overwrite files!

When the target file already exists, cp will overwrite the target file with the source file without displaying any warnings.

$ ls -lh src.txt dest.txt-rw-rw-r-- 1 user user 256 Sep 19 10:43 dest.txt-rw-rw-r-- 1 user user 128 Sep 19 10:43 src.txt$ cp src.txt dest.txt$ ls -lh src.txt dest.txt-rw-rw-r-- 1 user user 128 Sep 19 10:44 dest.txt-rw-rw-r-- 1 user user 128 Sep 19 10:43 src.txt

If you want the cp command to prompt interactively, you need to add the -i option.

$ cp -i src.txt dest.txtcp: overwrite 'dest.txt'?

We can control whether to overwrite the target file by entering y or n.

  • Recursively Copying Directories

Adding the -r option allows for recursive copying of directories, and similarly, no output will be printed if the copying is successful.

You can add the -v option to display the copying process.

# First, let's look at the structure of the src directory$ tree src/src/├── 1│   ├── c.txt│   └── d.txt├── a.txt└── b.txt
1 directory, 4 files
# Recursively copy the directory$ cp -rv src/ dest'src/' -> 'dest''src/1' -> 'dest/1''src/1/c.txt' -> 'dest/1/c.txt''src/1/d.txt' -> 'dest/1/d.txt''src/a.txt' -> 'dest/a.txt''src/b.txt' -> 'dest/b.txt'
# Now let's check the structure of the dest directory$ tree destdest├── 1│   ├── c.txt│   └── d.txt├── a.txt└── b.txt
1 directory, 4 files

✦•———-Advanced Usage Tips———-•✦

  • Backing Up Files

In backup scenarios, we may need to add the date and time to the target file name, so we can use it in conjunction with the date command mentioned earlier.

If you don’t remember how to use the date command, you can refer to the previous article “Daily Linux Command: date”.

$ cp src.txt src-$(date +'%Y%m%d.%H%M%S').txt.bak$ ls -lh src*-rw-rw-r-- 1 user user 128 Sep 19 10:55 src-20250919.105514.txt.bak-rw-rw-r-- 1 user user 128 Sep 19 10:53 src.txt
  • ⚠️ Copying Sparse Files

First, let’s introduce what a sparse file is.

In simple terms, a sparse file differs from a regular file in that it contains “holes” in between.

For example, a file that is 1GB in size does not actually occupy 1GB of disk space; it may only occupy a few tens of KB of storage space.

This situation is most common with virtual machine disk files.

The principle of sparse files is not complicated; the file system keeps track of which positions in the file contain logical “holes” and returns a value of 0 when reading data from those hole positions.

The benefit of using sparse files is that they can save a significant amount of disk space, and they can be created very quickly. For example, creating a 64GB virtual machine disk file that contains holes can be completed almost instantly. This is because the file system only marks in the file’s metadata that the file occupies “64GB” without actually issuing a 64GB IO write request to the disk. This allows for more efficient use of file system space.

However, in some cases, sparse files may be expanded, such as when transferring files containing holes over a network, compressing sparse files, or copying sparse files using the cp command.

Note that not all file systems support sparse files; most modern file systems (such as ext4/XFS/NTFS) do, but older file systems like FAT do not.

Next, let’s do a small experiment to copy a sparse file step by step to help everyone understand sparse files.

First, create a sparse file; it’s simple, just make the end position of the file greater than the actual file length to create holes.

# Create a sparse file with an 8KB hole$ truncate -s 8192 null.dat

To compare with a regular file containing 0 values, we will create another file of the same size.

$ dd if=/dev/zero of=zero.dat bs=1024 count=8

Next, use the ls command to check the logical sizes of these two files.

$ ls -lh null.dat zero.dat-rw-rw-r-- 1 user user 8.0K Sep 19 11:14 null.dat-rw-rw-r-- 1 user user 8.0K Sep 19 11:16 zero.dat

Both files have the same logical size of 8KB because the logical size attribute is stored in the file’s metadata.

Next, let’s use the du command to check the actual block storage space occupied by the files.

$ du -h null.dat zero.dat0       null.dat8.0K    zero.dat

The null.dat file actually occupies 0 bytes of storage space, while zero.dat occupies 8KB of storage space.

Now let’s check if their contents are the same by calculating their hash values:

$ sha256sum null.dat zero.dat9f1dcbc35c350d6027f98be0f5c8b43b42ca52b7604459c0c42be3aa88913d47  null.dat9f1dcbc35c350d6027f98be0f5c8b43b42ca52b7604459c0c42be3aa88913d47  zero.dat

The SHA256 of both files is the same, indicating that when reading the sparse file, the file system returned a value of 0.

However, the behavior of the cp command when copying sparse files varies across different operating systems; some systems will expand the holes by default, while others will not.

Using the --sparse=[auto/always/never] option, you can specify whether the cp command should expand the holes in sparse files.

The default is auto, always means not to expand, and never means to expand.

Now let’s look at the results of copying with always and never.

$ cp --sparse=always null.dat null_sparse.dat$ cp --sparse=never null.dat null_never.dat$ du -sh *.dat0       null.dat8.0K    null_never.dat0       null_sparse.dat8.0K    zero.dat$ sha256sum *.dat9f1dcbc35c350d6027f98be0f5c8b43b42ca52b7604459c0c42be3aa88913d47  null.dat9f1dcbc35c350d6027f98be0f5c8b43b42ca52b7604459c0c42be3aa88913d47  null_never.dat9f1dcbc35c350d6027f98be0f5c8b43b42ca52b7604459c0c42be3aa88913d47  null_sparse.dat9f1dcbc35c350d6027f98be0f5c8b43b42ca52b7604459c0c42be3aa88913d47  zero.dat

That’s all about the cp command.

Congratulations, you have gained more useful knowledge!✨

Leave a Comment