How to Create and Edit Text Files from the Command Line

To create a text file from the Linux command line, use touch filename.txt for an empty file, nano filename.txt to create and edit interactively, or echo "content" > filename.txt to create a file with content in one command. To edit an existing file, open it with a terminal editor like nano filename.txt or vim filename.txt. For appending content without opening an editor, use echo "more text" >> filename.txt (the >> appends rather than overwrites).

Files Without a Graphical Interface

Working entirely from the command line means creating and modifying text files without ever opening a graphical text editor window. This might sound limiting, but Linux’s command line provides an extensive toolkit for file creation and editing — from the simplest possible approach (an empty file with touch) to full-featured interactive editing (nano, vim) to programmatic content generation (echo, printf, redirection, heredocs) that is often faster and more scriptable than opening a graphical editor at all.

Understanding these techniques matters for more than convenience. Server administration happens almost entirely over SSH connections with no graphical interface available. Scripts that configure systems need to generate files programmatically rather than requiring someone to type content into an editor. Quick edits to configuration files are faster with a one-line command than launching an editor for a single-line change. And working comfortably in a terminal-only environment (a minimal server, a container, a recovery shell) requires knowing these techniques by heart.

This article covers every practical method for creating and editing text files from the Linux terminal: creating empty files, writing content with echo and printf, using redirection operators, heredocs for multi-line content, terminal editors for interactive editing, and practical techniques that combine these approaches for real-world tasks.

Creating Empty Files: touch

The simplest file creation tool, touch, creates an empty file if it does not exist:

$ touch newfile.txt
$ ls -la newfile.txt
-rw-r--r-- 1 sarah sarah 0 Feb 18 11:00 newfile.txt

The file exists with zero bytes of content.

touch’s Real Purpose: Updating Timestamps

touch‘s actual designed purpose is updating a file’s timestamp — its name is short for “touching” the file to mark it as recently accessed/modified, without changing its content:

$ touch existingfile.txt    # Updates modification time to now, content unchanged

This is useful in build systems and scripts that check file modification times to decide whether to rebuild something.

Creating Multiple Files at Once

$ touch file1.txt file2.txt file3.txt
$ touch report_{jan,feb,mar}.txt    # Creates report_jan.txt, report_feb.txt, report_mar.txt

Creating Files with Specific Timestamps

$ touch -t 202602180930 old_file.txt    # Sets timestamp to Feb 18, 2026, 09:30
$ touch -d "2026-01-01" newyear.txt     # Sets timestamp using a date string
$ touch -r reference.txt target.txt     # Sets target.txt's timestamp to match reference.txt

Writing Content Directly: echo and printf

echo: Simple Single-Line Content

$ echo "Hello, World!" > greeting.txt
$ cat greeting.txt
Hello, World!

The > operator redirects echo‘s output into the file, creating it if it does not exist, or overwriting it completely if it does.

Appending instead of overwriting:

$ echo "Second line" >> greeting.txt
$ cat greeting.txt
Hello, World!
Second line

The >> operator appends to the end of the file rather than replacing its contents.

Writing Multiple Lines with echo

$ echo -e "Line 1\nLine 2\nLine 3" > multiline.txt
$ cat multiline.txt
Line 1
Line 2
Line 3

The -e flag enables interpretation of backslash escapes like \n (newline), \t (tab).

printf: More Precise Formatting

printf offers more control over formatting than echo, especially useful in scripts:

$ printf "Name: %s\nAge: %d\n" "Sarah" 30 > info.txt
$ cat info.txt
Name: Sarah
Age: 30

printf does not automatically add a trailing newline (unlike echo), so you must include \n explicitly where needed.

Building a File Incrementally

$ echo "# Project TODO" > TODO.txt
$ echo "" >> TODO.txt
$ echo "- Fix login bug" >> TODO.txt
$ echo "- Update documentation" >> TODO.txt
$ echo "- Deploy to production" >> TODO.txt

$ cat TODO.txt
# Project TODO

- Fix login bug
- Update documentation
- Deploy to production

Heredocs: Writing Multi-Line Content Cleanly

For writing substantial multi-line content without repeated echo commands, a heredoc (here document) is the cleanest approach:

$ cat > config.txt << EOF
server {
    listen 80;
    server_name example.com;
    root /var/www/html;
}
EOF

This creates config.txt with exactly the content between << EOF and the matching EOF on its own line. The delimiter word (EOF is conventional but any word works) marks where the content ends.

Appending with Heredocs

$ cat >> config.txt << EOF

location /api {
    proxy_pass http://localhost:3000;
}
EOF

Heredocs with Variable Expansion

By default, heredocs expand shell variables:

$ NAME="Sarah"
$ cat > greeting.txt << EOF
Hello, $NAME!
Today is $(date +%A).
EOF

$ cat greeting.txt
Hello, Sarah!
Today is Wednesday.

Preventing variable expansion — quote the delimiter to treat the content as fully literal:

$ cat > script_template.sh << 'EOF'
#!/bin/bash
echo "The variable $HOME will NOT be expanded here"
EOF

$ cat script_template.sh
#!/bin/bash
echo "The variable $HOME will NOT be expanded here"

This is essential when writing scripts or configuration files that themselves contain $variable syntax that should be preserved literally, not expanded by your current shell.

Heredocs for Complex Configuration Files

Heredocs excel at generating configuration files in scripts:

#!/bin/bash
# Generate an nginx virtual host configuration
cat > /etc/nginx/sites-available/mysite.conf << EOF
server {
    listen 80;
    server_name ${DOMAIN};
    root ${WEBROOT};
    index index.html;

    location / {
        try_files \$uri \$uri/ =404;
    }
}
EOF

Note the escaped \$uri — this prevents the shell from trying to expand $uri as a shell variable (it does not exist in the script’s context; it is meant for nginx to interpret), while ${DOMAIN} and ${WEBROOT} remain unescaped so the script’s own variables ARE expanded.

heredoc with sudo (Writing to Root-Owned Files)

A common gotcha: sudo cat > /etc/protected_file << EOF does not work as expected, because the redirection (>) happens in your unprivileged shell, not under sudo. The correct pattern:

$ sudo tee /etc/protected_file << EOF > /dev/null
line 1
line 2
EOF

tee runs with sudo privileges and writes to the file, while the heredoc content still comes from your shell.

The tee Command: Writing While Viewing

tee writes its input both to a file and to standard output — useful for writing to a file while still seeing the content, and essential for writing to files requiring elevated privileges:

$ echo "New configuration line" | sudo tee -a /etc/somefile.conf
New configuration line

The -a (append) flag appends rather than overwrites. Without -a, tee overwrites the file (like >).

Writing to multiple files simultaneously:

$ echo "shared content" | tee file1.txt file2.txt file3.txt

Combining with sudo for privileged file editing without opening an editor:

$ echo "127.0.0.1 myapp.local" | sudo tee -a /etc/hosts

Terminal Text Editors: Interactive Editing

For substantial editing, an interactive terminal editor is more practical than constructing content through echo or heredocs.

nano: The Beginner-Friendly Editor

$ nano newfile.txt

Type content directly. Save with Ctrl+O, confirm filename with Enter, exit with Ctrl+X. See the dedicated nano article in this series for complete coverage of nano’s features.

vim/vi: The Powerful Modal Editor

$ vim newfile.txt

Vim starts in “Normal mode” where keys are commands, not text input. Press i to enter Insert mode and type content. Press Escape to return to Normal mode. Save and exit with :wq followed by Enter (or just save with :w, or quit without saving with :q!).

Absolute minimum vim survival commands:

i          # Enter insert mode (start typing)
Escape     # Return to normal mode
:w         # Save (write)
:q         # Quit
:wq        # Save and quit
:q!        # Quit without saving (force)

Choosing an Editor for Quick Edits

For a single quick edit to an existing file, nano is generally faster to use correctly for those unfamiliar with vim’s modal editing. For repeated editing tasks, learning vim’s efficiency pays dividends over time.

Reading and Verifying File Content

After creating or editing a file, verify its content:

$ cat filename.txt              # Print entire content
$ less filename.txt             # Page through content (q to quit)
$ head filename.txt             # First 10 lines
$ head -n 5 filename.txt        # First 5 lines
$ tail filename.txt             # Last 10 lines
$ tail -f logfile.txt           # Follow (watch new lines as they are added)
$ wc -l filename.txt            # Count lines
$ file filename.txt             # Identify the file type

Copying and Renaming Files from the Command Line

While not strictly “creating” files, these related operations are part of the same workflow:

$ cp original.txt copy.txt              # Copy a file
$ cp -i original.txt copy.txt           # Copy with confirmation before overwrite
$ mv oldname.txt newname.txt            # Rename (or move)
$ cp -r sourcedir/ destdir/             # Copy a directory recursively

Creating a file based on a template:

$ cp /etc/skel/.bashrc ~/new_config_starting_point

Practical Techniques for Common Tasks

Creating a Script File

$ cat > backup.sh << 'EOF'
#!/bin/bash
# Simple backup script
SOURCE="$HOME/Documents"
DEST="/backup/documents_$(date +%Y%m%d).tar.gz"
tar -czf "$DEST" "$SOURCE"
echo "Backup created: $DEST"
EOF

$ chmod +x backup.sh
$ ./backup.sh

Note the single-quoted 'EOF' — this prevents $HOME and $(date...) from being expanded when the heredoc is written, so they remain literal in the script and are correctly expanded later when the script actually runs.

Creating a Configuration File with Variable Substitution

#!/bin/bash
APP_NAME="myapp"
APP_PORT="8080"

cat > "/etc/${APP_NAME}/config.ini" << EOF
[server]
name = ${APP_NAME}
port = ${APP_PORT}
started = $(date)
EOF

Here the unquoted EOF allows variable expansion so the actual values are written into the file.

Appending a Line Only If It Does Not Already Exist

Avoiding duplicate entries when adding configuration lines:

$ grep -qxF "127.0.0.1 myapp.local" /etc/hosts || echo "127.0.0.1 myapp.local" | sudo tee -a /etc/hosts

grep -qxF checks quietly (-q) for an exact (-x) fixed-string (-F) match; if not found, the || triggers the append.

Creating an Empty File with Specific Permissions

$ install -m 600 /dev/null secretfile.txt
$ ls -la secretfile.txt
-rw------- 1 sarah sarah 0 Feb 18 11:30 secretfile.txt

install creates the file with the specified mode in one step, rather than touch followed by chmod.

Quickly Editing a Config File Value

Changing a single line in a config file without opening an editor, using sed:

$ sed -i 's/^port = .*/port = 9090/' config.ini

This finds any line starting with port = and replaces it entirely — useful for scripted configuration changes.

Creating a File with Today’s Date in the Name

$ touch "report_$(date +%Y-%m-%d).txt"
$ ls report_*.txt
report_2026-02-18.txt

Combining Multiple Files Into One

$ cat file1.txt file2.txt file3.txt > combined.txt
$ cat *.txt > all_combined.txt

Understanding Redirection Operators

A quick reference for the redirection operators used throughout this article:

Operator Effect
> Redirect stdout to file, overwriting existing content
>> Redirect stdout to file, appending to existing content
< Redirect file content as stdin to a command
2> Redirect stderr to file
2>> Append stderr to file
&> Redirect both stdout and stderr to file
2>&1 Redirect stderr to the same place as stdout
<< Heredoc: multi-line input until delimiter
<<< Herestring: single string as input

Herestring example:

$ grep "pattern" <<< "some text with pattern in it"
some text with pattern in it

Safety Practices When Creating and Editing Files

Always Confirm Before Overwriting Important Files

The > operator overwrites silently with no confirmation. Before running a command with > against an important file, double-check the filename:

$ echo "test" > important_config.txt    # DANGER if this file existed with content!

Consider using noclobber to prevent accidental overwrites in your interactive shell:

# Add to ~/.bashrc
set -o noclobber

With noclobber enabled, > refuses to overwrite an existing file (reporting an error), while >| explicitly forces the overwrite when you really want it.

Back Up Before Editing System Files

$ sudo cp /etc/important.conf /etc/important.conf.bak
$ sudo nano /etc/important.conf

Use Version Control for Important Scripts

For scripts and configuration files you edit repeatedly, consider tracking them in git:

$ cd ~/scripts
$ git init
$ git add backup.sh
$ git commit -m "Initial backup script"

This gives you a complete history of changes and the ability to revert if an edit introduces a problem.

Quick Reference: File Creation and Editing Commands

Task Command
Create empty file touch filename.txt
Create with single line echo "content" > filename.txt
Append a line echo "content" >> filename.txt
Create with multiple lines cat > filename.txt << EOF … EOF
Append multiple lines cat >> filename.txt << EOF … EOF
Write without variable expansion cat > file << 'EOF' … EOF
Edit interactively (beginner) nano filename.txt
Edit interactively (advanced) vim filename.txt
Write to privileged file echo "content" | sudo tee -a /path/file
View file content cat filename.txt
Page through content less filename.txt
Copy a file cp source.txt dest.txt
Rename a file mv old.txt new.txt
Combine files cat file1.txt file2.txt > combined.txt
Replace text in file sed -i 's/old/new/' filename.txt
Create with permissions set install -m 600 /dev/null filename.txt

Conclusion: The Terminal as a Complete Editing Environment

Creating and editing text files from the command line is not a limited fallback for when a graphical editor is unavailable — it is a complete, often more efficient way of working with text. touch for instant empty files, echo and printf for quick single-line content, heredocs for clean multi-line generation, tee for privileged writes, and nano or vim for interactive editing together cover every scenario you will encounter.

The techniques compound in scripts: a deployment script that generates configuration files with heredocs, a setup script that appends to /etc/hosts only if the entry does not already exist, a backup script that creates dated filenames automatically. This is the real power of command-line file creation — it is not just an alternative to graphical editing, it is programmable, repeatable, and scriptable in ways that clicking through a graphical editor never can be.

Master these techniques and working entirely within a terminal — whether by choice or because you are managing a remote server with no graphical interface — becomes not a limitation but simply another complete way of getting things done.

Hot this week

Type Traits in C++: Compile-Time Type Information

Master C++ type traits — learn how to query and transform types at compile time using , write your own type traits, and use them with if constexpr and SFINAE.

What Is the Difference Between sh, bash, and zsh Shells?

Learn the difference between sh, bash, and zsh shells in Linux — their history, compatibility, features, and how to choose the right shell for scripting and daily use.

How to View File Contents in Linux Without Opening an Editor

Learn how to view file contents in Linux using cat, less, more, head, tail, and other commands — without opening a text editor. Perfect for quick checks and log monitoring.

Understanding Pipes in Linux: Chaining Commands Together

Learn how Linux pipes work, how to chain commands together with the | operator, practical pipe examples, and the difference between pipes and redirection.

How to Redirect Output in Linux Commands

Learn how to redirect stdout, stderr, and stdin in Linux using >, >>, <, 2>, and 2>&1. Master output redirection with practical examples for scripts and everyday commands.

Topics

Type Traits in C++: Compile-Time Type Information

Master C++ type traits — learn how to query and transform types at compile time using , write your own type traits, and use them with if constexpr and SFINAE.

What Is the Difference Between sh, bash, and zsh Shells?

Learn the difference between sh, bash, and zsh shells in Linux — their history, compatibility, features, and how to choose the right shell for scripting and daily use.

How to View File Contents in Linux Without Opening an Editor

Learn how to view file contents in Linux using cat, less, more, head, tail, and other commands — without opening a text editor. Perfect for quick checks and log monitoring.

Understanding Pipes in Linux: Chaining Commands Together

Learn how Linux pipes work, how to chain commands together with the | operator, practical pipe examples, and the difference between pipes and redirection.

How to Redirect Output in Linux Commands

Learn how to redirect stdout, stderr, and stdin in Linux using >, >>, <, 2>, and 2>&1. Master output redirection with practical examples for scripts and everyday commands.

What Is the Linux Shell Profile and Bashrc File?

Learn the difference between .bashrc, .bash_profile, .profile, and /etc/profile in Linux — which files run when, what to put in each, and how to customize your shell startup.

Understanding Linux Software Sources and PPAs

Learn what PPAs are, how Ubuntu software sources work, how to safely add and remove PPAs, and the risks and benefits of using third-party software repositories.

How to Search for Installed Packages in Linux

Learn how to check if a package is installed in Linux and list all installed packages using dpkg -l, rpm -qa, apt list --installed, and dnf list installed.

Related Articles

Popular Categories