Shell by Example: Temporary Files POSIX + Bash

Temporary files are essential for shell scripts that need to store intermediate data. The mktemp command creates them safely.

Basic temporary file with mktemp:

Edit
#!/bin/sh
tmpfile=$(mktemp)
echo "Created temp file: $tmpfile"
echo "Hello, temp!" >"$tmpfile"
cat "$tmpfile"
rm "$tmpfile"
Output:
Created temp file: /tmp/tmp.stab000000
Hello, temp!

mktemp creates unique files in $TMPDIR (or /tmp):

Edit
#!/bin/sh
echo "TMPDIR: ${TMPDIR:-/tmp}"
Output:
TMPDIR: /tmp

Custom prefix with template:

Edit
#!/bin/sh
tmpfile=$(mktemp /tmp/myapp.XXXXXX)
echo "Custom prefix: $tmpfile"
rm "$tmpfile"
Output:
Custom prefix: /tmp/myapp.stab00

At least 6 X’s are required for the random suffix. This ensures sufficient randomness in the filename.

Edit
#!/bin/sh
tmpfile=$(mktemp /tmp/data.XXXXXX)
echo "6 X's works: $tmpfile"
rm "$tmpfile"

tmpfile=$(mktemp /tmp/longer.XXXXXXXXXX)
echo "More X's also works: $tmpfile"
rm "$tmpfile"
Output:
6 X's works: /tmp/data.stab00
More X's also works: /tmp/longer.stab000001

Create temporary directory:

Edit
#!/bin/sh
tmpdir=$(mktemp -d)
echo "Created temp dir: $tmpdir"
touch "$tmpdir/file1.txt"
touch "$tmpdir/file2.txt"
ls "$tmpdir"
rm -rf "$tmpdir"
Output:
Created temp dir: /tmp/tmp.stab000000
file1.txt
file2.txt

Custom directory template:

Edit
#!/bin/sh
tmpdir=$(mktemp -d /tmp/myapp.XXXXXX)
echo "Custom temp dir: $tmpdir"
rm -rf "$tmpdir"
Output:
Custom temp dir: /tmp/myapp.stab00

Bash

You should always clean up temp files using trap.

Edit
#!/bin/bash
demo_trap_cleanup() {
    local tmpfile
    tmpfile=$(mktemp)
    trap 'rm -f "$tmpfile"' EXIT

    echo "Working with $tmpfile"
    echo "data" >"$tmpfile"
    # Even if script exits early, cleanup runs
}
demo_trap_cleanup
Output:
Working with /tmp/tmp.stab000000

Multiple temp files with cleanup:

Edit
#!/bin/sh
cleanup_files() {
    (
        tmpfile1=$(mktemp)
        tmpfile2=$(mktemp)
        tmpdir=$(mktemp -d)
        trap 'rm -f "$tmpfile1" "$tmpfile2"; rm -rf "$tmpdir"' EXIT

        echo "Files: $tmpfile1, $tmpfile2"
        echo "Dir: $tmpdir"
        # Work with temp files...
    )
}
echo "Cleanup demo:"
cleanup_files
Output:
Cleanup demo:
Files: /tmp/tmp.stab000000, /tmp/tmp.stab000001
Dir: /tmp/tmp.stab000002

Named pipe (FIFO) for inter-process communication:

Edit
#!/bin/sh
tmpfifo=$(mktemp -u) # -u just prints name, doesn't create
mkfifo "$tmpfifo"
echo "Created FIFO: $tmpfifo"

# Producer (background)
echo "message" >"$tmpfifo" &

# Consumer
read -r msg <"$tmpfifo"
echo "Received: $msg"

rm "$tmpfifo"
Output:
Created FIFO: /tmp/tmp.stab000000
Received: message

Bash

Using process substitution instead of temp files. This avoids creating explicit temp files:

Edit
#!/bin/bash
echo -e "banana\napple\ncherry" >/tmp/file1.txt
echo -e "apple\nbanana\ndate" >/tmp/file2.txt

diff <(sort /tmp/file1.txt) <(sort /tmp/file2.txt)

rm /tmp/file1.txt /tmp/file2.txt
Output:
--- /dev/fd/63
+++ /dev/fd/62
@@ -1,3 +1,3 @@
 apple
 banana
-cherry
+date

POSIX alternative using named pipes:

Edit
#!/bin/sh
compare_sorted() {
    tmp1=$(mktemp)
    tmp2=$(mktemp)
    trap 'rm -f "$tmp1" "$tmp2"' EXIT

    printf "b\na\nc\n" | sort >"$tmp1"
    printf "c\na\nd\n" | sort >"$tmp2"
    echo "Diff of sorted inputs:"
    diff "$tmp1" "$tmp2" || true
}
compare_sorted
Output:
Diff of sorted inputs:
--- /tmp/tmp.stab000000
+++ /tmp/tmp.stab000001
@@ -1,3 +1,3 @@
 a
-b
 c
+d

Secure temp file patterns. Don’t use predictable names like /tmp/myapp.$$ - the PID is predictable and creates a race condition. Use mktemp and set restrictive permissions:

Edit
#!/bin/sh
tmpfile=$(mktemp)
chmod 600 "$tmpfile"
ls -la "$tmpfile"
rm "$tmpfile"
Output:
-rw------- 1 root root 0 Jan  1  2025 /tmp/tmp.stab000000

Temp file in specific directory using a template

Edit
#!/bin/sh
customtmp=$(mktemp /tmp/myapp.XXXXXX)
echo "Custom location: $customtmp"
rm "$customtmp"
Output:
Custom location: /tmp/myapp.stab00

Atomic file operations with temp files:

Edit
#!/bin/sh
atomic_write() {
    target="$1"
    content="$2"

    tmpfile=$(mktemp "$(dirname "$target")/tmp.XXXXXX")
    echo "$content" >"$tmpfile"
    mv "$tmpfile" "$target"
}

atomic_write /tmp/atomic_test.txt "Atomic content"
cat /tmp/atomic_test.txt
rm /tmp/atomic_test.txt
Output:
Atomic content

Collect output from multiple processes:

Edit
#!/bin/sh
collect_output() {
    tmpdir=$(mktemp -d)
    trap 'rm -rf "$tmpdir"' EXIT

    # Simulate parallel tasks
    echo "result1" >"$tmpdir/task1"
    echo "result2" >"$tmpdir/task2"

    # Collect results
    echo "Collected results:"
    cat "$tmpdir"/*
}
collect_output
Output:
Collected results:
result1
result2

Here-document to temp file:

Edit
#!/bin/sh
tmpfile=$(mktemp)
cat >"$tmpfile" <<'EOF'
Line 1
Line 2
Line 3
EOF
echo "From heredoc temp file:"
cat "$tmpfile"
rm "$tmpfile"
Output:
From heredoc temp file:
Line 1
Line 2
Line 3

In-memory temp file using /dev/shm (Linux):

Edit
#!/bin/sh
if [ -d /dev/shm ]; then
    ramtmp=$(mktemp /dev/shm/myapp.XXXXXX)
    echo "RAM-based temp: $ramtmp"
    rm "$ramtmp"
else
    echo "/dev/shm not available"
fi
Output:
RAM-based temp: /dev/shm/myapp.stab00

« Directories | Arithmetic »