Linux & Bash · Part I · Module 3 · Creating and Changing Files and Directories
Copying and Moving: cp, mv and What They Overwrite
Two commands, both of which look obvious and neither of which is. cp duplicates something; mv relocates or renames it. What makes them worth a careful chapter is that both decide what your command means by checking the filesystem first — the same words produce different results depending on whether the destination already exists — and that both will overwrite an existing file completely silently, returning success. This is the first point in the course where a correctly typed command with a correct exit status can leave you worse off than before you ran it, and the habits that prevent that are cheap to learn now.
Foundation18 min readLinuxPart IFundamentalsFilesData Safety
Part I · Module 3 · Chapter 3.2 · Copying and Moving
1. Two Jobs, One Shape
cp SOURCE DESTINATION duplicate it — the original stays
mv SOURCE DESTINATION relocate or rename it — the original is goneBoth take at least two operands, and Chapter 1.5's rule about operand position applies with force: the last one is the destination, and the others are sources. Swap them and you have asked for something quite different.
Both are external programs, so — per Chapter 1.7 — their exact messages vary a little between systems. The behaviour taught here does not.
2. cp — The Simple Cases
Copy a file to a new name in the same directory:
$ pwd
/home/engineer/project/rtl
$ ls
alu.sv counter.sv
$ cp alu.sv alu_backup.sv
$ ls
alu.sv alu_backup.sv counter.svTwo files now exist with the same contents. The original is untouched — that is the whole difference from mv.
Copy a file into a directory, keeping its name:
$ pwd
/home/engineer/project
$ cp rtl/alu.sv docs
$ ls docs
alu.svThe destination docs is a directory that exists, so cp put the file inside it and kept the name. Copy several at once, and the last operand must be a directory:
$ cp rtl/alu.sv rtl/counter.sv docs
$ ls docs
alu.sv counter.svEvery path form from Module 2 works in either position:
$ cp ../rtl/alu.sv . # from a sibling, into here
$ cp /etc/os-release ~/notes/ # absolute source, home destination
$ cp alu.sv ../docs/alu_copy.sv # up and across, with a new nameNote the second line: . and ~ are doing exactly what Chapter 2.3 said they do, and cp has no idea they were ever involved — the shell replaced ~ before cp started.
3. How cp Decides What You Meant
This is the rule behind every surprise in the chapter, so it is worth stating on its own:
cplooks at the destination. If it is an existing directory, the file goes inside it. Otherwise the destination is treated as a file name.
Both halves are reasonable. Together they create a trap:
$ pwd
/home/engineer/project
$ ls
docs rtl scripts sim
$ cp rtl/alu.sv backup
$ ls -l backup
-rw-r--r-- 1 engineer engineer 482 Mar 20 14:20 backupThere is no directory called backup, so cp did the second thing: it created a file called backup, containing a copy of alu.sv. Read the listing with Chapter 2.5 — the leading - confirms it is an ordinary file, not a directory.
Nothing failed. The exit status was zero. You asked for a file named backup and you got one.
4. Both Commands Overwrite Without Asking
Here is the behaviour this chapter exists for.
$ printf 'the new work\n' > draft.txt
$ printf 'a week of edits\n' > report.txt
$ cat report.txt
a week of edits
$ cp draft.txt report.txt
$ echo $?
0
$ cat report.txt
the new workThe previous contents of report.txt are gone. Not in a recycle bin, not recoverable. cp printed nothing, asked nothing, and reported success — because from its point of view it succeeded completely.
mv behaves the same way:
$ printf 'ONE\n' > m1.txt
$ printf 'TWO\n' > m2.txt
$ mv m1.txt m2.txt
$ cat m2.txt
ONE
$ ls m1.txt
ls: cannot access 'm1.txt': No such file or directoryTwo files became one. m2.txt's contents were replaced, and m1.txt no longer exists because mv moved it.
The options that make it ask
Two options change that, and both are worth knowing:
$ cp -i draft.txt report.txt
cp: overwrite 'report.txt'? n-i is interactive: ask before overwriting, and do nothing if you answer no.
$ cp -n draft.txt report.txt
$ cat report.txt
a week of edits-n is no-clobber: never overwrite, and do not ask either. The existing file survived and the copy simply did not happen.
Both options exist for mv as well. -i suits you at a prompt; -n suits a command you want to be safe without a human present.
A third option is useful for a different reason:
$ cp -v rtl/alu.sv docs/
'rtl/alu.sv' -> 'docs/alu.sv'-v is verbose: say what was done. It does not prevent anything, but it tells you the destination the command actually resolved — which is exactly the thing §3's trap gets wrong.
5. Copying a Directory Needs -r
$ pwd
/home/engineer/project
$ cp rtl backup_rtl
cp: -r not specified; omitting directory 'rtl'cp copies files. To copy a directory and everything inside it, ask for recursion:
$ cp -r rtl backup_rtl
$ ls backup_rtl
alu.sv counter.sv-r is for recursive: descend into the directory and copy what is found, all the way down. Chapter 1.5's rule holds — it is a short option, and cp -rv combines two.
6. The cp -r Destination Trap
Now the trap that catches people for years. The same command produces two different results depending on something you did not type.
In a session, destination missing:
$ pwd
/home/engineer/project
$ ls
docs rtl scripts sim
$ cp -r rtl backup
$ ls backup
alu.sv counter.svbackup did not exist, so it was created as a copy of rtl. The files sit directly inside it.
Now run the identical command again, with backup now present:
$ cp -r rtl backup
$ ls backup
alu.sv counter.sv rtl
$ ls backup/rtl
alu.sv counter.svThis time rtl was placed inside backup, adding a level nobody asked for. Both runs are cp applying §3's rule consistently: an existing directory destination means put it in here.
7. mv — Rename and Move Are the Same Thing
A point that saves confusion: Linux has no separate rename command, because renaming is moving.
$ pwd
/home/engineer/project/rtl
$ mv counter.sv counter_8bit.sv
$ ls
alu.sv counter_8bit.svThe file stayed in the same directory and got a different name. Chapter 2.1 explained that a directory holds entries, and that a file's name lives in that entry. Changing the name and changing which directory holds the entry are the same operation on the same thing — so one command does both.
Moving into another directory:
$ pwd
/home/engineer/project
$ mv notes.txt docs/
$ ls docs
notes.txtMoving and renaming at once:
$ mv rtl/alu.sv docs/alu_reference.svSeveral files into one directory, with the destination last:
$ mv a.txt b.txt c.txt docs/mv follows exactly the same destination rule as cp: an existing directory means into it; anything else is a name. And it needs no -r for directories, because moving a directory does not involve copying what is inside it:
$ mv sim/run1 sim/run1_old8. The Failures Worth Recognising
Overwriting something you wanted — §4. The fix is a habit, not an option: look before you write.
$ ls -l report.txt
-rw-r--r-- 1 engineer engineer 8192 Mar 19 09:30 report.txtIf that command prints a line, the destination exists and your copy will replace it. If it prints No such file or directory, you are creating something new. One command, complete certainty.
The file named after a directory you thought existed — §3. cp x.txt backup with no backup directory gives you a file called backup. Use the trailing slash.
Copying a directory without -r — §5. This one is safe: it refuses and tells you.
A typo in the destination:
$ mv report.txt docs/reprot.txtNothing failed. You now have a correctly moved file with a misspelled name, and ls docs is how you find out. -v would have shown it immediately.
Copying a directory and losing its hidden files. Chapter 2.6 warned that patterns beginning with * skip names starting with a dot. A copy written with a pattern can silently leave configuration behind:
$ cp -r project/* backup/ # dotfiles in project/ are NOT copiedCopying the directory itself, rather than a pattern of its contents, avoids the problem entirely:
$ cp -r project backup_project # everything, including hidden entriesWhy the pattern misses them is Chapter 3.5's subject, and the full rule is Module 9's.
9. Why This Matters in Engineering Work
Two situations, no semiconductor knowledge needed.
Keep a copy before you edit something you did not write. Before changing a configuration or a script that other people depend on:
$ cp -v setup.sh setup.sh.bak
'setup.sh' -> 'setup.sh.bak'Two seconds, and the original is recoverable. This is the cheapest insurance available on a system with no undo, and it is the habit most often skipped by people who later wish they had it.
Never copy onto a results directory. Output directories are the classic place for §6's trap to do damage: copy new results onto an existing directory and you get a mixture of two runs with no record of which file came from where. Chapter 3.1's one-directory-per-run convention exists partly to make this impossible — a fresh directory cannot be a stale one.
Part II returns to both habits where results and reproducibility are the whole subject.
10. Practice
The starting tree:
/home/engineer/project
├── docs
│ └── readme.md
├── rtl
│ ├── alu.sv
│ └── counter.sv
└── simYour working directory is /home/engineer/project for every question.
Question 1. cp rtl/alu.sv docs — where does the file land, and what is it called? Which fact about docs decided that?
Question 2. cp rtl/alu.sv archive — there is no archive. What exactly exists afterwards, and how would ls -l archive prove it?
Question 3. Rewrite the command in Question 2 so that it fails loudly instead of producing the wrong thing.
Question 4. cp docs/readme.md rtl/alu.sv runs and prints nothing. What has happened to alu.sv? What would you have run first to know in advance?
Question 5. cp -r rtl sim — sim exists. Give the full path of the copied alu.sv. Now suppose sim had not existed: give the path in that case.
Question 6. You want to rename sim to sim_old. Write the command, and say why no -r is needed even though it is a directory.
Question 7. mv rtl/counter.sv rtl/conuter.sv succeeds. What went wrong, why did nothing report it, and which option would have shown you?
Question 8. Moving a large directory takes a second one day and twenty minutes the next, with the same command. Give the likely reason, using a term from Chapter 2.1.
11. Remember
cpduplicates and leaves the original.mvrelocates, and the original is gone. The last operand is always the destination.- Both decide the destination's meaning by looking at it. An existing directory means inside it; anything else is treated as a file name.
- A missing destination directory becomes a file of that name. The trailing slash —
backup/— says you meant a directory, and turns the mistake into an error. - Both overwrite an existing file silently and report success. There is no confirmation and no undo.
-iasks first,-nrefuses to overwrite,-vsays what was actually done. cpneeds-rfor a directory and refuses safely without it.mvnever needs it.cp -r src desthas two outcomes: ifdestis missing it becomes a copy ofsrc; if it exists,srcis nested inside it. Running the same command twice therefore gives different results.- Rename and move are one operation, because a name is just an entry in a directory.
ls -lon the destination before you write to it is the whole safety practice, and it costs one command.- A pattern like
project/*skips hidden entries. Copy the directory itself when you mean everything.
Both commands in this chapter can destroy a file. The next one does nothing else — and unlike these two, it has no gentler mode to fall back on.
Where this fits
Part of the Linux & Bash curriculum.
