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
touchsets 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.
cpandmvwrite over the target without asking;-imakes them ask.- Copying a directory requires
-r;-ppreserves 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.