Guides

How to create a file in Linux: the touch command, echo, cat and tee

How to create a file in Linux: touch for empty files, echo and heredocs for content, sudo tee for root-owned files, fallocate for size, touch timestamps.

Published ~7 min read
On this page

Short answer: to create a file in Linux, run touch file.txt. It creates an empty file, or only updates the timestamps if the file already exists. For content, redirect output: echo "text" > file.txt writes (and overwrites), >> appends, a heredoc writes several lines. For a root-owned path, pipe into sudo tee.

any Linux
touch notes.txt                          # empty file (or new timestamps if it exists)
echo "hello" > hello.txt                 # file with one line; overwrites!
echo "again" >> hello.txt                # append a line
printf 'a\nb\n' > two.txt                # exact content, no surprises
echo "127.0.0.1 app.local" | sudo tee -a /etc/hosts   # into a file only root may write

The outputs on this page come from Debian 12 with GNU coreutils 9.1, bash 5.2.15 and util-linux 2.38.1, run in a scratch directory on 21 October 2026, partly as an unprivileged user. The nano and vim keys follow their documentation. Ubuntu, Rocky Linux and AlmaLinux ship the same GNU touch.

Ways to create a file, and which one to use

MethodCommandIf the file existsBest for
touchtouch file.txtContent kept, timestamps updatedEmpty files, markers, timestamps
Redirect> file.txtEmptiedAn empty file, or emptying one
echoecho "text" > file.txtOverwrittenOne line
Appendecho "text" >> file.txtLine added at the endLogs, adding to config
printfprintf 'a\nb\n' > file.txtOverwrittenExact content in scripts
Heredoccat > file.txt <<'EOF'OverwrittenConfig files, several lines
teeecho "x" | sudo tee fileOverwritten (-a appends)Files only root may write
Editornano file.txtOpened for editingTyping by hand
Given sizefallocate -l 1G file.imgGrown if smaller, never shrunkDisk images, swap, tests

touch: create an empty file

touch takes one or more names and creates each file that does not exist yet, with a size of 0. With brace expansion, one line creates a numbered series:

Example output
$ touch a.txt b.txt c.txt
$ touch file{1..3}.log
$ ls -l notes.txt file1.log
-rw-r--r-- 1 root root 0 Oct 21 19:46 file1.log
-rw-r--r-- 1 root root 0 Oct 21 19:46 notes.txt

That is the main reason to pick touch over > file: on an existing file it changes nothing but the timestamps, so touching hello.txt left both its lines in place, while > hello.txt emptied it to 0 bytes. touch does not create folders. touch nodir/x.txt fails with cannot touch 'nodir/x.txt': No such file or directory; create the path first with mkdir -p.

echo, printf and >: a file with content

The shell, not the command, creates the file named after >. That is why any command that prints something can fill a new file, and why > on its own already creates an empty one:

Example output
$ echo "first line" > hello.txt
$ echo "second" >> hello.txt
$ cat hello.txt
first line
second

> truncates an existing file without asking, which is how working config files get lost. set -o noclobber makes bash refuse; when you do mean to overwrite, >| forces it:

Example output
$ set -o noclobber
$ echo hi > two.txt
bash: two.txt: cannot overwrite existing file
$ echo hi >| two.txt

echo adds a newline unless you pass -n (echo nonl | wc -c counts 5 bytes, printf nonl 4), and its handling of -e and backslashes differs between bash, dash and /bin/echo. In scripts, printf writes exactly what you give it: printf '%s\n' "$value" > file. The redirection guide covers 2>, &> and the rest.

Several lines: cat and heredocs

cat > notes.txt on its own waits for you to type; every line goes into the file until you press Ctrl+D on an empty line. In a script or a copy-paste snippet, a heredoc does the same without the interaction:

bash
cat > app.conf <<'EOF'
port=8080
home=$HOME
EOF
Example output
$ cat app.conf
port=8080
home=$HOME

The quotes around 'EOF' matter. Quoted, the text is written exactly as typed, $HOME included. Unquoted (<<EOF), the shell expands variables and command substitutions first, and the same line came out as home=/root. Quote it for config files that contain $, such as nginx configs; leave it unquoted when you want values filled in.

Creating a file as root: sudo tee

sudo echo "x" > /etc/myapp.conf fails with Permission denied, because the redirection is done by your own shell before sudo starts, and your user cannot write to /etc. Let a root process open the file instead: tee writes its input to the file and to the screen.

any Linux
echo "max_connections = 200" | sudo tee /etc/myapp.conf > /dev/null   # create or overwrite
echo "127.0.0.1 app.local"    | sudo tee -a /etc/hosts > /dev/null     # append

sudo tee /etc/myapp/override.conf > /dev/null <<'EOF'
[server]
port = 8080
EOF

> /dev/null only hides tee’s copy on the screen. Forget -a on a file like /etc/hosts and tee replaces it with that one line. sudo sh -c 'echo x > /etc/file' works too, but quoting gets awkward fast.

With an editor: nano or vim

nano notes.txt or vim notes.txt opens a file that does not exist yet as an empty buffer. Nothing is created on disk until you save.

  • nano: type, then Ctrl+O and Enter to save, Ctrl+X to leave. The shortcuts are listed at the bottom of the screen.
  • vim: press i to start typing, Esc when done, then :wq and Enter to save and quit. If you are stuck, the guide to exiting vim has every way out.

A file of a given size: fallocate, truncate, head

any Linux
fallocate -l 10M swaptest.img          # reserves real disk blocks at once
truncate -s 1G sparse.img              # a 1 GiB file that uses no space (sparse)
head -c 2M /dev/zero > dd.img          # writes 2 MiB of zeros, works everywhere
Example output
$ ls -lh *.img
-rw-r--r-- 1 root root 2.0M Oct 21 19:46 dd.img
-rw-r--r-- 1 root root 1.0G Oct 21 19:46 sparse.img
-rw-r--r-- 1 root root  10M Oct 21 19:46 swaptest.img
$ du -h *.img
2.0M    dd.img
0       sparse.img
10M     swaptest.img

ls shows the size a file claims, du the space it really takes. The truncate file claims 1 GiB and uses nothing until data is written, which is fine for testing an upload limit and useless for anything that must own its space. A swap file must not have holes: the swapon man page says truncate creates them, that a fallocate file may count as one on some filesystems, and calls dd from /dev/zero the most portable way. The swap guide uses fallocate and falls back to dd. truncate -s 0 file is also the clean way to empty a log that a program keeps open.

touch timestamps: -a, -m, -d, -t, -r, -c

Every file has an access time (atime), a modification time (mtime) and a change time (ctime), and ext4 also records a birth time. stat shows them all:

Example output
$ stat plain.txt
  File: plain.txt
  Size: 0         	Blocks: 0          IO Block: 4096   regular empty file
Device: 8,1	Inode: 3542724     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-10-21 19:46:38.416147151 +0000
Modify: 2026-10-21 19:46:38.416147151 +0000
Change: 2026-10-21 19:46:38.416147151 +0000
 Birth: 2026-10-21 19:46:38.416147151 +0000
OptionExampleEffect
-dtouch -d '2026-01-15 09:30' fSet atime and mtime to a date in free form
-dtouch -d '2 days ago' fRelative dates work too: yesterday 14:00, 2 days ago
-ttouch -t 202603011200.30 f[[CC]YY]MMDDhhmm[.ss], the POSIX format
-mtouch -m -d '2025-12-24 18:00' fChange only the modification time
-atouch -a -d '2024-06-01' fChange only the access time
-rtouch -r file.txt copy.txtCopy the times of another file
-ctouch -c maybe.txtNever create; only update if it exists
-htouch -h -d 2020-02-02 linkChange a symlink itself, not its target

In the test, touch -m moved only the mtime and left the atime from the previous step, and -a did the reverse. The ctime cannot be set: after touch -d '2026-01-15 09:30', Access and Modify showed January while Change showed the moment of the touch, because changing timestamps is itself a change. A date touch cannot parse, such as touch -d blah f, fails with touch: invalid date format 'blah' and exit status 1.

A reference file for find -newer

A timestamp you set on purpose makes a handy marker. Touch a file with the start of a period, and find -newer lists everything modified after it:

any Linux
touch -d '2026-10-01' /tmp/since
find /var/www -type f -newer /tmp/since       # files changed since 1 October

That is a quick first look after a suspected intrusion or a deploy that went wrong; the find guide has the -mtime and -mmin forms.

Permissions of a new file: umask

New files start from mode 666 (nobody gets execute), minus your umask. With the common 0022 that gives 644; directories start from 777 and come out as 755:

Example output
$ umask
0022
$ touch m1; mkdir m1d; stat -c '%A %a %n' m1 m1d
-rw-r--r-- 644 m1
drwxr-xr-x 755 m1d
$ (umask 077; touch m2; stat -c '%A %a %n' m2)
-rw------- 600 m2
$ (umask 002; touch m3; stat -c '%A %a %n' m3)
-rw-rw-r-- 664 m3

touch has no option for the mode. For a file that must never be readable by others, such as one with passwords or API keys, create it with the right mode from the start instead of fixing it afterwards: install -m 600 /dev/null secret.env created an empty -rw------- file in one step. To change the mode of an existing file, see the chmod guide.

Errors when creating a file

Message ends withMeaningFix
Permission deniedNo write permission on the directory (or sudo with a redirect)Work in a directory you own, or use sudo tee
No such file or directoryA folder in the path does not existmkdir -p
Is a directoryA redirect (>) names an existing directoryPick a file name inside it
cannot overwrite existing filenoclobber is on>|
invalid date formattouch -d could not parse the dateUse YYYY-MM-DD HH:MM
Read-only file systemThe filesystem is mounted read-onlyRead-only file system
No space left on deviceDisk full, or out of inodesNo space left on device

Frequently asked

How do I create an empty file in Linux?

Run touch filename. It creates an empty file if none exists and only updates the timestamps of an existing one, so it never destroys content. > filename also creates an empty file, but it empties an existing one.

How do I create a file with text in it from the command line?

Use echo "text" > file.txt for one line (it overwrites an existing file) and >> to append. For several lines, use a heredoc: cat > file.txt <<'EOF', then the lines, then EOF on a line of its own. printf is the safer choice in scripts because it writes exactly what you give it.

Why does sudo echo "text" > /etc/file give Permission denied?

Your own shell opens the file for the redirection before sudo starts, so the write happens without root rights. Pipe into sudo tee instead: echo "text" | sudo tee /etc/file > /dev/null, or sudo tee -a to append.

How do I change a file's timestamp with touch?

touch -d '2026-01-15 09:30' file sets the access and modification time. -m changes only the modification time, -a only the access time, and -r other_file copies the times of another file. The change time (ctime) cannot be set: it always becomes the current time.

Related articles

All guides