Skip to content
academia.sh

Lesson 07 / 20

Creating, Copying, and Moving

Creating files and setting timestamps, copying's overwrite behavior, the case where the target is a directory, and what moving means at the file system level.

Contents

The previous lesson made the tree readable, but the data/raw directory was empty. This lesson fills the tree: measurement files are created, processed copies are produced, and a backup directory is set up.

Three commands will be used — touch, cp, mv — and all three have situations where they silently lose data. Which rules give rise to these situations matters more than the commands themselves.

Creating Files and Timestamps

The touch command’s real job is setting timestamps; creating an empty file when given a name that does not exist is a secondary behavior.

$ touch data/raw/measurement-01.csv
$ ls -l data/raw
total 0
-rw-r--r-- 1 student student 0 Jul 26 19:02 measurement-01.csv

The size is zero: the file exists but has no content. A file existing and a file having content are separate things; a directory entry and an inode have been created, but no data block has been allocated.

Output redirection is used to write content:

$ printf 'zaman,sicaklik,nem\n08:00,21.4,55\n12:00,24.9,49\n' > data/raw/measurement-01.csv
$ cat data/raw/measurement-01.csv
zaman,sicaklik,nem
08:00,21.4,55
12:00,24.9,49

The > sign writes the command’s output to a file instead of the terminal. The grammar of redirection is the subject of the Shell Programming course; here it is used only to produce a file. The point to note is this: > empties the target file without warning. Writing to an existing file with > deletes the old content irreversibly.

Two more measurement files are created the same way:

$ printf 'zaman,sicaklik,nem\n08:00,19.8,61\n12:00,23.1,52\n' > data/raw/measurement-02.csv
$ printf 'zaman,sicaklik,nem\n08:00,22.6,58\n12:00,26.3,44\n' > data/raw/measurement-03.csv
$ ls -l data/raw
total 12
-rw-r--r-- 1 student student 47 Jul 26 19:02 measurement-01.csv
-rw-r--r-- 1 student student 47 Jul 26 19:03 measurement-02.csv
-rw-r--r-- 1 student student 47 Jul 26 19:03 measurement-03.csv

On an existing file, touch does not touch the content, it only sets the timestamps to that moment. To set a specific time, the -t option is used:

$ touch /tmp/sample.txt
$ ls -l /tmp/sample.txt
-rw-r--r-- 1 student student 0 Jul 26 19:03 /tmp/sample.txt
$ touch -t 202603110930 /tmp/sample.txt
$ ls -l /tmp/sample.txt
-rw-r--r-- 1 student student 0 Mar 11 09:30 /tmp/sample.txt

The -t value is in YYYYMMDDhhmm format and is defined in POSIX. The -d option in GNU tools accepts human-readable date strings but is not portable; -t is preferred in scripts.

Setting a timestamp is not just a matter of tidiness: most backup and build tools do an “is the source newer than the target” comparison, and this comparison relies on the modification time.

Copying

The cp command takes two arguments: source and target. Two different rules apply depending on what the target is.

If the target is an existing directory, the source is copied into it, under the same name:

$ cp data/raw/measurement-01.csv data/processed/
$ ls -l data/processed
total 4
-rw-r--r-- 1 student student 47 Jul 26 19:03 measurement-01.csv

If the target is not a directory, the source is copied under that name:

$ cp data/raw/measurement-01.csv data/processed/summary-01.csv
$ ls -l data/processed
total 8
-rw-r--r-- 1 student student 47 Jul 26 19:03 measurement-01.csv
-rw-r--r-- 1 student student 47 Jul 26 19:03 summary-01.csv

These two rules are the source of the most common mistake: if the target directory’s name is misspelled, the directory is not found, and the command creates the copy as a file under that wrong name. No error message appears. Putting a slash at the end of the target catches this mistake: when targetdir/ is written and no such directory exists, the command gives an error.

Overwriting Is Silent

By default, cp writes over the target without asking:

$ cat data/processed/summary-01.csv
zaman,sicaklik,nem
08:00,21.4,55
12:00,24.9,49
$ cp data/raw/measurement-02.csv data/processed/summary-01.csv
$ cat data/processed/summary-01.csv
zaman,sicaklik,nem
08:00,19.8,61
12:00,23.1,52

The old content is gone and cannot be brought back. There is no warning, and the exit status is zero.

The -i option asks before overwriting:

$ cp -i data/raw/measurement-03.csv data/processed/summary-01.csv
cp: overwrite 'data/processed/summary-01.csv'? n

On a negative answer, the file does not change, and the command returns a non-zero exit status. -i is defined in POSIX and is the recommended habit for interactive use.

There is also an option to protect an existing target without asking at all, but it is not portable; in GNU tools, when -n is given, a warning is printed that this option’s behavior may change. In scripts, the target’s existence is tested first; the option is not relied on.

Copying Directories

Directories are not copied by default; -r is needed for recursive copying.

$ cp -r data/raw archive/raw-backup
$ ls -l archive/raw-backup
total 12
-rw-r--r-- 1 student student 47 Jul 26 19:04 measurement-01.csv
-rw-r--r-- 1 student student 47 Jul 26 19:04 measurement-02.csv
-rw-r--r-- 1 student student 47 Jul 26 19:04 measurement-03.csv

Copies are new files: a new inode, a new timestamp. If the timestamps should be preserved, -p is added:

$ cp -rp data/raw archive/raw-p
$ ls -l archive/raw-p
total 12
-rw-r--r-- 1 student student 47 Jul 26 19:02 measurement-01.csv
-rw-r--r-- 1 student student 47 Jul 26 19:03 measurement-02.csv
-rw-r--r-- 1 student student 47 Jul 26 19:03 measurement-03.csv

Comparing the two listings, the difference is clear: without -p all files carry the moment of copying, with -p they keep their original times. -p also tries to preserve permissions and ownership. This detail is decisive in backups; a backup that has lost its timestamps cannot answer the question “which version is newer.”

In directory copying, the target rule turns into a trap:

$ cp -r /tmp/demo/source /tmp/demo/target
$ find /tmp/demo | sort
/tmp/demo
/tmp/demo/target
/tmp/demo/target/source
/tmp/demo/target/source/a.txt
/tmp/demo/source
/tmp/demo/source/a.txt

If the target directory already exists, the source is placed inside it. When the same command is run a second time, the result does not change, because target/source now exists too and the content is overwritten. But if it is run while the target does not exist, the target is created as a copy of the source. The same command giving two different results depends on whether the target existed beforehand.

Moving

mv looks like copying on the surface, but at the file system level it is an entirely different operation.

$ ls -li data/processed
total 8
22212 -rw-r--r-- 1 student student 47 Jul 26 19:03 measurement-01.csv
22545 -rw-r--r-- 1 student student 47 Jul 26 19:03 summary-01.csv
$ mv data/processed/summary-01.csv data/processed/daily-summary.csv
$ ls -li data/processed
total 8
22545 -rw-r--r-- 1 student student 47 Jul 26 19:03 daily-summary.csv
22212 -rw-r--r-- 1 student student 47 Jul 26 19:03 measurement-01.csv

The inode number has not changed: 22545 is the same under both the old and new name. The only thing that changed is the directory entry. The name is not a property of the file; it is a mapping kept in the directory. Changing the name does not touch the file.

The measurable consequence of this is that moving within the same file system has constant cost, independent of file size. Renaming a one-byte file and a one-gigabyte file takes the same time, because no data is read or written.

This does not hold when the same operation is done between different file systems. Inode numbers are meaningful only within their own file system; an entry cannot be carried from one device to another. In this case mv copies the content and deletes the source — the time is proportional to file size, and if the operation is interrupted midway, the target can be left incomplete.

If the target is a directory, mv follows the same naming rule too:

$ mv data/processed/measurement-01.csv docs/
$ ls docs
measurement-01.csv
$ ls data/processed
daily-summary.csv

mv also overwrites silently, and the -i option makes it ask. Unlike copying, here two files are lost at once: the target’s old content is deleted, and the source disappears too.

Summary

  • touch sets timestamps; creating a nonexistent file as empty is a secondary behavior, and a specific time can be given with -t.
  • In copying, if the target is an existing directory, the source is copied into it under the same name; otherwise it is copied under the given name. A misspelled directory name silently creates a file.
  • cp and mv write over the target without asking; -i makes them ask.
  • Copying a directory requires -r; -p preserves timestamps, permissions, and ownership.
  • Moving within the same file system changes only the directory entry: the inode number is preserved, and the cost is independent of file size.
  • Moving between different file systems turns into a copy-and-delete operation; the cost is proportional to size and carries the risk of being interrupted midway.

Next Step

All three commands in this lesson can lose data, but each does it by overwriting something. The deletion command, on the other hand, destroys directly, and the file system has no “undo” operation. The next lesson takes up what deletion means at the kernel level, under what condition a deleted file is still alive, and how to make verification a habit before running destructive commands.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close