, ,

Copy, Move, and Delete Files From the Linux Command Line (Linux for Beginners, Part 4)

The five commands that do almost all file work in Linux: cp, mv, rm, mkdir and ln. Learn the quiet defaults that catch everyone, plus hard versus symbolic links.

Linux for Beginners · Part 4 of 24

The command line has no recycle bin. Delete a file and it is unlinked immediately: no confirmation, no trash folder, no thirty day grace period. That fact scares people away from the four commands that do almost all the work of a working day. It should not. Learn how cp, mv, rm and ln behave, plus the two or three defaults that catch everyone in week one, and you can move data around a server faster than any file manager.

Here is the first thing Linux does that surprises newcomers. You try to copy a folder and it refuses:

$ cp project backup
cp: -r not specified; omitting directory 'project'
$ cp -r project backup
$ ls backup
README.md  notes.txt  src

That refusal is not a bug. cp copies one file by default, and a directory is a container of many files, so it makes you ask for the recursive copy on purpose. Once you see the pattern behind each command, the rest stops being scary.

Start here
Five commands cover most file work: cp to copy, mv to move or rename, rm to delete, mkdir to make a folder, ln to link. The danger is not the commands, it is three quiet defaults: cp needs -r for folders, mv overwrites the target without asking, and rm deletes with no way back. Get those three into muscle memory and you are safe.

This part is for two readers. If you are a college passout following along on a laptop, type every command yourself, because reading them does nothing. If you are already working in IT and just need the practical version, jump to the sections on rm safety and on hard versus symbolic links, which is where real incidents come from. Everything below runs the same on Ubuntu, Debian, and the RHEL family; the file tools are GNU coreutils on all of them.

The five verbs you will use every day

Before the deep end, here is the whole toolkit on one card. Keep it open in another tab for a week and you will not need it after that.

CommandDoesEveryday example
lsList what is herels -lh
cpCopy a file, keep the originalcp app.conf app.conf.bak
mvMove or renamemv draft.txt final.txt
rmDelete, no undorm old.log
mkdirMake a directorymkdir -p a/b/c
touchCreate an empty file, or bump its timestamptouch notes.txt
ln -sMake a symbolic linkln -s /opt/app/current app
findSearch the tree by name, age, sizefind . -name '*.log'

Two quick ones before we slow down. mkdir -p a/b/c creates every missing parent in the path in one shot and does not complain if they already exist, which is why scripts use it constantly. touch file makes an empty file if none exists, and updates the modified time if it does. That timestamp trick matters later when you hunt for files by age.

Copying, and the directory trap

The grammar of cp is always the same: source first, destination last. cp a.txt b.txt makes b.txt a copy of a.txt. Add -r when the source is a folder. The flag you will reach for most is -a, the archive copy, which preserves permissions, ownership, and timestamps instead of stamping everything with the current time. When you back up a config directory, cp -a is almost always what you actually mean.

The default that bites: does the destination already exist?

Here is the single most confusing thing about copying folders, and it trips up people with years of experience. When you run cp -r src dest, the result depends on whether dest already exists.

cp -r src destdest does NOT existdest becomes a copy of srcdest already existssrc is placed inside destResult: ls destthe files that were in srcResult: ls destdest/src/ the filesSame command, two outcomes, decided by whether the target folder exists

Watch it happen. The second copy lands one level deeper than the first, and nothing warned you:

$ ls
src
$ cp -r src dest        # dest did not exist
$ ls dest
file1  file2
$ cp -r src dest        # now dest DOES exist
$ ls dest
file1  file2  src       # src landed inside

If you meant to overwrite the contents rather than nest a folder, copy the contents with a trailing slash and a wildcard, or use cp -a src/. dest/, which copies what is inside src including hidden files. Two other flags are worth memorizing: -i asks before overwriting an existing file, and -n refuses to overwrite at all. On a shared server, cp -n is a cheap insurance policy.

Renaming is just moving

Linux has no separate rename command in daily use. mv does both jobs, because renaming a file is the same operation as moving it to a new name in the same directory. mv draft.txt final.txt renames. mv final.txt /home/dp/docs/ moves. mv across the same filesystem is instant no matter how large the file, because it only rewrites a directory entry; it does not copy bytes.

$ ls
report.txt  report_final.txt
$ mv report_final.txt report.txt
$ ls
report.txt

Look closely at that sequence. The original report.txt is gone, silently overwritten by report_final.txt, and there was no prompt and no backup. This is the default that costs people real work.

Where this bites
A junior admin runs mv new.conf app.conf to deploy an update and does not notice app.conf already held a hand tuned config nobody committed to version control. It is gone, and there is no copy. Two habits prevent this for good: use mv -i when you are not certain the target is empty, and pass mv --backup=numbered on anything that matters, which keeps the old file as app.conf.~1~ instead of destroying it.

Deleting, with no net

When you rm a file, Linux removes the directory entry pointing to its data and, if that was the last entry, marks the space free. There is no trash folder on a plain server. Recovery means specialist tools and a lot of luck. So the mental model for rm is simple: whatever you name, assume it is gone the instant you press Enter.

$ ls
keep.conf  old.log  old.tmp
$ rm *.log *.tmp
$ ls
keep.conf

That worked because the shell expanded the wildcards before rm ever ran. You did not hand rm the text *.log; the shell replaced it with the matching filenames first, then ran the command. That expansion is the source of the most famous beginner disaster.

You typerm *.logShell expandsa.log b.log c.logrm receives3 real namesThe command never sees the star. The shell resolves it first, so a stray space changes everything.
Gotcha
You mean to type rm *.tmp but your finger adds a space: rm * .tmp. The shell expands the lone * to every file in the folder, and rm deletes all of them, then complains it cannot find a file literally named .tmp. The lesson is to read the whole line before Enter, and on anything destructive, run ls *.tmp first to preview exactly what the wildcard matches.

A real opinion: do not alias rm to rm -i

Half the tutorials tell you to put alias rm='rm -i' in your shell config so every delete asks for confirmation. I think that advice does more harm than good, and I have seen why. It trains you to hit y without reading, because the prompt appears every single time even for a file you obviously want gone. Then you log into a production box that does not have your alias, muscle memory fires, and the safety you leaned on is not there. Better options: use rm -I, the capital variant from GNU coreutils, which prompts once before deleting three or more files or recursing into a directory, so it warns on the dangerous cases and stays quiet on the trivial ones. And on the truly important machines, slow your own hands down instead of outsourcing caution to a prompt you have taught yourself to ignore.

One more rule that has saved more servers than any alias: never run rm -rf with a variable in the path unless you are certain it is set. rm -rf $DIR/ becomes rm -rf / when DIR is empty. Quote your variables and check them first.

Hard links and symbolic links

A filename in Linux is not the file. The real file is an inode, a numbered record of the data and its permissions, and a name is just a label pointing at that inode. This is why links exist, and why the two kinds behave so differently. A hard link is a second name for the same inode. A symbolic link is a tiny separate file that holds a path, a signpost pointing at a name.

inode 1234567the actual data blocksoriginal.txthard.txtsoft.txthard links pointstraight at the inodea symlink points at the NAME above it

The difference is not academic. Watch what happens to each when the original name is deleted. The -i flag on ls prints the inode number in the first column, and the number after the permissions is the link count.

$ echo 'v1' > original.txt
$ ln original.txt hard.txt        # hard link
$ ln -s original.txt soft.txt     # symbolic link
$ ls -li
1234567 -rw-r--r-- 2 dp dp  3 Jul  3 09:14 hard.txt
1234567 -rw-r--r-- 2 dp dp  3 Jul  3 09:14 original.txt
1234570 lrwxrwxrwx 1 dp dp 12 Jul  3 09:14 soft.txt -> original.txt

$ rm original.txt                 # delete the first name
$ cat hard.txt
v1
$ cat soft.txt
cat: soft.txt: No such file or directory

Read the output carefully. original.txt and hard.txt share inode 1234567 and show a link count of 2, so they are genuinely the same file under two names. Deleting one name drops the count to 1 and the data survives under the other. The symlink has its own inode, 1234570, and points at the text original.txt; once that name is gone, the symlink dangles and points at nothing. Hard links cannot cross filesystems or point at directories; symlinks can do both, which is why symlinks are what you use in practice, for example to point /opt/app/current at whichever release directory is live.

Finding files without a mouse

Wildcards match names in one directory. When you need to search a whole tree by name, age, or size, that job belongs to find. Its grammar is a starting directory, then tests that narrow the results. find . -name '*.log' lists every log file under the current directory and everything below it. Quote the pattern so the shell hands the star to find instead of expanding it too early.

$ find . -name '*.log' -mtime +7
./var/app-2026-06-20.log
./var/app-2026-06-22.log
$ find . -name '*.log' -mtime +7 -delete

The -mtime +7 test means modified more than seven days ago, which is where the touch timestamp habit pays off. Always run the find once to see the list before you add -delete. On filesystems where other users can write, the GNU findutils manual recommends piping through xargs with null separators instead, because it handles spaces and odd characters in names safely:

$ find /var/tmp/stuff -mtime +90 -print0 | xargs -0 rm

The -print0 and xargs -0 pair separate filenames with a null byte, the one character that can never appear inside a path, so a file named with a space or a newline cannot break the command apart.

Real interview question
What is the difference between a hard link and a symbolic link, and what happens to each when you delete the original file? A strong answer: a hard link is another directory entry for the same inode, so the data survives as long as any hard link remains and deleting the original name is harmless. A symbolic link stores a path to a name, so it breaks the moment the target name disappears. Bonus points for adding that hard links cannot span filesystems or link directories, while symlinks can do both.
Try it yourself
Prove the inode idea with your own hands. Make a folder, create a file, hard link it, and confirm both names share one inode and a link count of 2.

mkdir -p ~/lab && cd ~/lab
echo 'hello' > a.txt
ln a.txt b.txt
Verify with exactly this: stat -c '%h %i %n' a.txt b.txt
You should see the same inode number and a link count of 2 on both lines. Now run rm a.txt then cat b.txt and watch the data survive.
$ stat -c '%h %i %n' a.txt b.txt
2 1899024 a.txt
2 1899024 b.txt

Myth versus reality

Most beginner mistakes with these commands trace back to a handful of wrong assumptions. Here are the ones worth unlearning today.

What people believeWhat actually happens
rm sends files to a trash I can restoreThere is no trash on a plain server. The data is unlinked at once and recovery is not something you can count on.
mv warns me before overwritingIt overwrites the target silently. Use mv -i or mv –backup to be warned or keep the old copy.
cp -r src dest always copies into destOnly if dest already exists. If it does not, dest becomes the copy of src instead.
Deleting a file breaks its hard linkNo. The data lives as long as any hard link remains, because they share one inode.
rm handles the wildcard itselfThe shell expands the wildcard first. A stray space in rm * .tmp can wipe the whole folder.

Copying, moving, and deleting are the commands you will run thousands of times, so the payoff from understanding their defaults now is enormous. Next in the series we move from handling files to controlling who is allowed to touch them, starting with users, groups, and the sudo command. If you want the wider map of where Linux sits next to the platforms it runs on, the Cloud for Beginners and VMware for Beginners guides cover the layers above it. Open a terminal, make a scratch folder, and break a few files on purpose. That is the fastest way to trust these commands.

Linux for Beginners · Part 4 of 24
« Previous: Part 3  |  Complete Guide  |  Next: Part 5

References

GNU Coreutils: cp invocation
GNU Coreutils: ln invocation and link behavior
GNU Findutils: safely deleting files with find

About The Author


Discover more from Journal of Intelligent Infrastructure – By Dr Pranay Jha

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure - By Dr Pranay Jha

Subscribe now to keep reading and get access to the full archive.

Continue reading