touch
Create an empty file, or move a timestamp
touch does two jobs. Given a name that does not exist it creates an empty file; given one that
does, it leaves the contents alone and moves the timestamps to now. Neither job is what > does,
and the difference matters: a redirect empties whatever it lands on.
A file carries three times. touch sets the access time and the modification time, separately if
you ask, and -d or -t puts them wherever you want rather than at the current moment. The
third, the change time, records when the inode itself was last altered, and there is no flag for
it: setting the other two is itself a change, so it moves to now whatever you asked for.
The usual reason to set a time deliberately is to make a reference point, which find can then compare every other file against.
Sample files used on this page
Every example below was run against these files. Recreate them to follow along.
site the tree the cp, mv and rm pages use as well; every timestamp in it is set deliberately, so one file's time can be copied onto another and the two compared
site:
total 16
drwxr-xr-x 2 user user 4096 Jun 15 10:00 assets
drwxr-xr-x 2 user user 4096 Jun 15 10:00 backups
-rw-r--r-- 1 user user 36 Jun 1 09:00 index.html
lrwxrwxrwx 1 user user 9 Jun 18 09:00 latest.css -> style.css
-rw-r--r-- 1 user user 33 Jun 20 09:00 style.css
site/assets:
total 4
-rw-r--r-- 1 user user 35 Jun 10 09:00 logo.svg
site/backups:
total 0
notes.txt one line, beside site/ rather than inside it
Rebuild before deploying.
Creating an empty file
A name that does not exist becomes an empty regular file. A name that does exist keeps everything it had.
Create an empty file
touch report.txt && stat -c "%a %s %F %n" report.txt
Zero bytes, and a mode from your umask. %s is the size and %F the kind of thing it is, so this says the file exists and has nothing in it.
Show output
644 0 regular empty file report.txt
Create several at once
touch a.txt b.txt c.txt && ls *.txt
Every argument is a name. notes.txt was already there and appears because the glob matched it, not because touch did anything to it.
Show output
a.txt
b.txt
c.txt
notes.txt
Touch a file that already has something in it
cat notes.txt; touch notes.txt; cat notes.txt
The contents are untouched. That is the point of the name. Only the timestamps moved.
Show output
Rebuild before deploying.
Rebuild before deploying.
See what a redirect does instead
cat notes.txt; : > notes.txt; wc -c notes.txt
> file truncates to zero on the spot, before anything is written, so using it to make sure a file exists destroys the contents of one that already did. That idiom wants touch.
Show output
Rebuild before deploying.
0 notes.txt
Update a file only if it is already there
touch -c missing.txt; ls missing.txt
-c (--no-create) drops the creating behaviour and reports no error when the file is absent. Useful when the point is to move a timestamp and creating an empty file would be wrong.
Show output
ls: cannot access 'missing.txt': No such file or directory
See the mode a new file gets
umask 077; touch tight.txt; umask 022; touch loose.txt; stat -c "%a %n" tight.txt loose.txt
touch asks for 666 and the umask takes bits away, so 022 gives 644. There is no -m here as there is on mkdir: change the mode afterwards with chmod if the default is wrong.
Show output
600 tight.txt
644 loose.txt
Try a path whose directory does not exist
touch site/2026/report.csv; echo "exit $?"
touch creates a file and never a directory. mkdir -p on the parent first is the pairing a script wants.
Show output
touch: cannot touch 'site/2026/report.csv': No such file or directory
exit 1
Create a file you have no permission for
touch /etc/tips; echo "exit $?"
Write permission on the directory decides it, /etc here, and sudo is the usual answer.
Show output
touch: cannot touch '/etc/tips': Permission denied
exit 1
The three timestamps
Every file carries an access time, a modification time and a change time. touch sets the first two. None of the three is a creation time, which Linux did not record at all until recently and still does not expose through these tools.
Read all three
stat --printf "access %.19x\nmodify %.19y\nchange %.19z\n" site/index.html
The fixture set access and modify to the same moment. The change time is when the inode was last written. For this file that was when the fixture created it.
Show output
Your output will differ: the change time is whenever the file arrived on your machine
access 2026-06-01 09:00:00
modify 2026-06-01 09:00:00
change 2026-09-04 10:38:12
Move both to now
touch site/index.html && ls -l site/index.html
A bare touch on an existing file sets the access and modification times to the current moment. This is the form that makes a build system think a source file changed. ls -l shows the modification time, which is the one you nearly always mean.
Show output
Your output will differ: the timestamp is the moment you ran it
-rw-r--r-- 1 user user 36 Sep 5 07:39 site/index.html
Move only the access time
touch -a -d "2026-02-02 08:00" site/index.html && stat --printf "access %.19x\nmodify %.19y\n" site/index.html
-a leaves the modification time where it was. ls -lu reads the access time back if you would rather not run stat, and a tool that sorts by age is almost always reading the modification time instead.
Show output
access 2026-02-02 08:00:00
modify 2026-06-01 09:00:00
Move only the modification time
touch -m -d "2026-03-03 08:00" site/index.html && stat --printf "access %.19x\nmodify %.19y\n" site/index.html
-m sets the modification time instead, and it is the one you usually want. --time=atime and --time=mtime are the long spellings.
Show output
access 2026-06-01 09:00:00
modify 2026-03-03 08:00:00
Fail to set the change time
touch -d "2020-01-01" site/index.html && ls -l site/index.html && ls -lc site/index.html
ls -lc reads the change time where a plain ls -l reads the modification time. The modification time went back to 2020 and the change time went to now, because altering the inode is itself a change. Nothing sets it, and that is why an audit tool reads it.
Show output
Your output will differ: the change time is the moment you ran it
-rw-r--r-- 1 user user 36 Jan 1 2020 site/index.html
-rw-r--r-- 1 user user 36 Sep 5 07:39 site/index.html
Choosing the time
-d takes anything date understands and -t takes a fixed numeric stamp. Both beat running the command at the right moment.
Set a date and time
touch -d "2026-01-01 09:30" site/index.html && stat -c "%.19y %n" site/index.html
-d (--date) parses a wide range of formats. A date with no time gives midnight.
Show output
2026-01-01 09:30:00 site/index.html
Use a relative phrase
touch -d "2 hours ago" site/index.html && ls -l site/index.html
"yesterday", "last monday" and "+3 days" all work too. Handy for making a file old enough to be caught by a find -mtime you are testing.
Show output
Your output will differ: the timestamp is two hours before you ran it
-rw-r--r-- 1 user user 36 Sep 5 05:40 site/index.html
Use the numeric stamp instead
touch -t 202601011200 site/index.html && stat -c "%.19y %n" site/index.html
-t takes CCYYMMDDhhmm with no punctuation and no room for interpretation. Worth preferring in a script, where -d parsing a string differently on another machine is a real risk.
Show output
2026-01-01 12:00:00 site/index.html
Add seconds to the stamp
touch -t 202601011200.30 site/index.html && stat -c "%.19y %n" site/index.html
A dot and two digits after the minutes. Without them the seconds are zero.
Show output
2026-01-01 12:00:30 site/index.html
Copy the time from another file
touch -r site/style.css site/index.html && stat -c "%.19y %n" site/style.css site/index.html
-r (--reference) takes both times from the file you name. This is how you restore a timestamp you have just destroyed by editing something, provided you kept a copy.
Show output
2026-06-20 09:00:00 site/style.css
2026-06-20 09:00:00 site/index.html
Set several files to one time
touch -d "2025-04-04" site/index.html site/style.css && ls -l site/index.html site/style.css
Every argument gets the same time. Note what ls does with a date this old: past about six months it prints the year in place of the time of day, so the 00:00 is not visible here.
Show output
-rw-r--r-- 1 user user 36 Apr 4 2025 site/index.html
-rw-r--r-- 1 user user 33 Apr 4 2025 site/style.css
Symlinks
A symlink has timestamps of its own, and by default touch sets the ones on the file at the far end. stat is the other way round and reports on the link unless you pass -L, so the two need reading carefully together.
Touch through the link
touch -d "2026-05-05" site/latest.css && stat -c "%.19y %n" site/latest.css site/style.css
latest.css points at style.css, and it is style.css that moved. The link kept its own time, which stat is showing because it does not follow a link on its own.
Show output
2026-06-18 09:00:00 site/latest.css
2026-05-05 00:00:00 site/style.css
Touch the link itself
touch -h -d "2026-05-05" site/latest.css && stat -c "%.19y %n" site/latest.css site/style.css
-h (--no-dereference) moves the link and leaves the target alone. The two lines have swapped over from the example above.
Show output
2026-05-05 00:00:00 site/latest.css
2026-06-20 09:00:00 site/style.css
What it is actually for
Creating an empty file is the demonstration. Setting a time on purpose is the job.
Make a reference point for find
touch -d "2026-06-15" marker && find site -newer marker | sort
Anything modified after the marker comes back. find -newer compares against a file rather than a duration. Counting days backwards with -mtime is harder to get right.
Show output
site
site/assets
site/backups
site/latest.css
site/style.css
Touch a directory rather than a file
touch -d "2026-08-08" site/assets && stat -c "%.19y %n" site/assets site/assets/logo.svg
A directory has timestamps like anything else, and setting them says nothing about what is inside. logo.svg did not move.
Show output
2026-08-08 00:00:00 site/assets
2026-06-10 09:00:00 site/assets/logo.svg
Read a modification time without stat
date -r site/style.css "+%F"
date -r prints one file's modification time in whatever format you ask for. Shorter than a stat when a script wants the date as a string.
Show output
2026-06-20
Leave a marker that a step has run
touch .setup-done && ls -a | grep setup
A file whose contents nobody reads and whose existence is the whole message. A later run tests for it with [ -e .setup-done ] and skips the work.
Show output
.setup-done
Confirm the mode survives
chmod 400 notes.txt && touch notes.txt; echo "exit $?"; stat -c "%a %n" notes.txt
A read-only file you own can still be touched, and it keeps its mode. Permissions and timestamps are separate pieces of the inode, and touch only ever writes the second.
Show output
exit 0
400 notes.txt
Handle a name that begins with a dash
touch -- -notes.txt && ls -d -- -notes.txt
Without -- the shell hands touch a filename and touch reads it as flags. ./-notes.txt works as well.
Show output
-notes.txt