Shell by Example: Writing Files POSIX + Bash

Shell provides several ways to write data to files using redirection operators. This example covers common file writing patterns.

Basic write with > (overwrites existing file):

Edit
#!/bin/sh
echo "Hello, World!" >/tmp/output.txt
echo "Created file with: $(cat /tmp/output.txt)"
Output:
Created file with: Hello, World!

Append with >> (adds to end of file):

Edit
#!/bin/sh
echo "First line" >/tmp/append.txt
echo "Second line" >>/tmp/append.txt
echo "Third line" >>/tmp/append.txt
echo "Appended file:"
cat /tmp/append.txt
Output:
Appended file:
First line
Second line
Third line

Write multiple lines with here-document:

Edit
#!/bin/sh
cat >/tmp/multiline.txt <<'EOF'
This is line 1
This is line 2
This is line 3
EOF
echo "Here-document file:"
cat /tmp/multiline.txt
Output:
Here-document file:
This is line 1
This is line 2
This is line 3

Here-document with variable expansion:

Edit
#!/bin/sh
name="Alice"
cat >/tmp/template.txt <<EOF
Hello, $name!
Today is $(date)
Your home is $HOME
EOF
echo "Template with variables:"
cat /tmp/template.txt
Output:
Template with variables:
Hello, Alice!
Today is Wed Jan  1 10:00:00 UTC 2025
Your home is /root

Write without newline using printf:

Edit
#!/bin/sh
printf "No newline here" >/tmp/nonewline.txt
printf " - continued\n" >>/tmp/nonewline.txt
cat /tmp/nonewline.txt
Output:
No newline here - continued

Redirect stdout and stderr:

Edit
#!/bin/sh
echo "Redirect stdout (1) and stderr (2):"

# Stdout only to file
ls /tmp >/tmp/stdout.txt 2>/dev/null

# Stderr only to file
ls /nonexistent 2>/tmp/stderr.txt

# Both to same file
ls /tmp /nonexistent >/tmp/both.txt 2>&1

# Both to different files
ls /tmp /nonexistent >/tmp/out.txt 2>/tmp/err.txt

echo "  Stderr captured: $(cat /tmp/stderr.txt)"
Output:
Redirect stdout (1) and stderr (2):
  Stderr captured: ls: cannot access '/nonexistent': No such file or directory

Discard output:

Edit
#!/bin/sh
echo "Discarding output:"
ls /nonexistent 2>/dev/null # Discard stderr
echo "  Stderr discarded (no error shown)"
Output:
Discarding output:
  Stderr discarded (no error shown)

Tee - write to file and stdout simultaneously:

Edit
#!/bin/sh
echo "Using tee:"
echo "This goes to both" | tee /tmp/tee.txt
echo "File contains: $(cat /tmp/tee.txt)"

echo "Append with tee -a:"
echo "Appended line" | tee -a /tmp/tee.txt >/dev/null
cat /tmp/tee.txt
Output:
Using tee:
This goes to both
File contains: This goes to both
Append with tee -a:
This goes to both
Appended line

Write from pipeline:

Edit
#!/bin/sh
echo "Pipeline to file:"
seq 1 5 | grep -v 3 >/tmp/pipeline.txt
cat /tmp/pipeline.txt
Output:
Pipeline to file:
1
2
4
5

Atomic write (write to temp, then rename):

Edit
#!/bin/sh
atomic_write() {
    tmpfile=$(mktemp)
    echo "Important data" >"$tmpfile"
    mv "$tmpfile" "$1"
}

atomic_write /tmp/atomic.txt
echo "Atomic write result: $(cat /tmp/atomic.txt)"
Output:
Atomic write result: Important data

Write with file descriptor:

Edit
#!/bin/sh
exec 3>/tmp/fd.txt
echo "Line 1" >&3
echo "Line 2" >&3
exec 3>&- # Close the file descriptor
echo "File descriptor write:"
cat /tmp/fd.txt
Output:
File descriptor write:
Line 1
Line 2

Append with file descriptor:

Edit
#!/bin/sh
exec 4>>/tmp/fd.txt
echo "Appended line" >&4
exec 4>&-
cat /tmp/fd.txt
Output:
Appended line

Create file if not exists, don’t overwrite:

Edit
#!/bin/sh
if [ ! -f /tmp/nooverwrite.txt ]; then
    echo "New content" >/tmp/nooverwrite.txt
fi
echo "Safe write (no overwrite): $(cat /tmp/nooverwrite.txt)"
Output:
Safe write (no overwrite): New content

Truncate file to empty:

Edit
#!/bin/sh
echo "content" >/tmp/truncate.txt
: >/tmp/truncate.txt # or > /tmp/truncate.txt
echo "After truncate, size: $(wc -c </tmp/truncate.txt) bytes"
Output:
After truncate, size: 0 bytes

Bash

Bash provides noclobber option to prevent overwriting:

Edit
#!/bin/bash
set -o noclobber
echo "test" >existingfile.txt  # Fails if file exists
echo "test" >|existingfile.txt # Force overwrite
set +o noclobber

Write to multiple files at once:

Edit
#!/bin/sh
echo "Multiple files" | tee /tmp/file1.txt /tmp/file2.txt >/dev/null
echo "File1: $(cat /tmp/file1.txt)"
echo "File2: $(cat /tmp/file2.txt)"
Output:
File1: Multiple files
File2: Multiple files

Write binary data:

Edit
#!/bin/sh
printf '\x48\x65\x6c\x6c\x6f' >/tmp/binary.txt
echo "Binary write: $(cat /tmp/binary.txt)"
Output:
Binary write: Hello

Write with specific permissions:

Edit
#!/bin/sh
(
    umask 077
    echo "Secret" >/tmp/secret.txt
)
stat -c 'Permissions: %A' /tmp/secret.txt 2>/dev/null || stat -f 'Permissions: %Sp' /tmp/secret.txt
Output:
Permissions: -rw-------

« Reading Files | File Paths »