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.
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 writeThe 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
| Method | Command | If the file exists | Best for |
|---|---|---|---|
| touch | touch file.txt | Content kept, timestamps updated | Empty files, markers, timestamps |
| Redirect | > file.txt | Emptied | An empty file, or emptying one |
| echo | echo "text" > file.txt | Overwritten | One line |
| Append | echo "text" >> file.txt | Line added at the end | Logs, adding to config |
| printf | printf 'a\nb\n' > file.txt | Overwritten | Exact content in scripts |
| Heredoc | cat > file.txt <<'EOF' | Overwritten | Config files, several lines |
| tee | echo "x" | sudo tee file | Overwritten (-a appends) | Files only root may write |
| Editor | nano file.txt | Opened for editing | Typing by hand |
| Given size | fallocate -l 1G file.img | Grown if smaller, never shrunk | Disk 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:
$ 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.txtThat 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:
$ 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:
$ set -o noclobber
$ echo hi > two.txt
bash: two.txt: cannot overwrite existing file
$ echo hi >| two.txtecho 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:
cat > app.conf <<'EOF'
port=8080
home=$HOME
EOF$ cat app.conf
port=8080
home=$HOMEThe 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.
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+Oand Enter to save,Ctrl+Xto leave. The shortcuts are listed at the bottom of the screen. - vim: press
ito start typing,Escwhen done, then:wqand 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
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$ 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.imgls 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:
$ 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| Option | Example | Effect |
|---|---|---|
-d | touch -d '2026-01-15 09:30' f | Set atime and mtime to a date in free form |
-d | touch -d '2 days ago' f | Relative dates work too: yesterday 14:00, 2 days ago |
-t | touch -t 202603011200.30 f | [[CC]YY]MMDDhhmm[.ss], the POSIX format |
-m | touch -m -d '2025-12-24 18:00' f | Change only the modification time |
-a | touch -a -d '2024-06-01' f | Change only the access time |
-r | touch -r file.txt copy.txt | Copy the times of another file |
-c | touch -c maybe.txt | Never create; only update if it exists |
-h | touch -h -d 2020-02-02 link | Change 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:
touch -d '2026-10-01' /tmp/since
find /var/www -type f -newer /tmp/since # files changed since 1 OctoberThat 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:
$ 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 m3touch 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 with | Meaning | Fix |
|---|---|---|
| Permission denied | No write permission on the directory (or sudo with a redirect) | Work in a directory you own, or use sudo tee |
| No such file or directory | A folder in the path does not exist | mkdir -p |
| Is a directory | A redirect (>) names an existing directory | Pick a file name inside it |
| cannot overwrite existing file | noclobber is on | >| |
| invalid date format | touch -d could not parse the date | Use YYYY-MM-DD HH:MM |
| Read-only file system | The filesystem is mounted read-only | Read-only file system |
| No space left on device | Disk full, or out of inodes | No 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.