Home / Alt manpages / pdfattach(1)

  • pdfattach(1)
  • User command
  • linux

Attach a File to a PDF Safely with pdfattach

pdfattach adds a file to an existing PDF without touching either the input PDF or the file being attached. This guide uses pdfattach from Poppler 24.02.0, provided by poppler-utils. Allow about ten minutes once you have the PDF and the file ready.

You need a readable input PDF, a readable attachment, and a directory you can write to. These are ordinary user operations: sudo is not normally required.

1. Check the installed command

Confirm the binary and package version before relying on examples. This step is read-only:

$ command -v pdfattach
/usr/bin/pdfattach
$ pdfattach -v
pdfattach version 24.02.0
Copyright 2005-2024 The Poppler Developers - http://poppler.freedesktop.org
$ dpkg-query -W -f='${Package} ${Version}\n' poppler-utils
poppler-utils 24.02.0-1ubuntu9.9

The local manual page calls the utility a PDF embedded-file creator and documents this command shape:

pdfattach [options] input-PDF-file file-to-attach output-PDF-file

Keep the three paths in that order. The last one is a new PDF, not an output directory.

2. Attach a file to a new PDF

Pick a destination that does not already exist. The example keeps the original invoice and adds a plain-text note as an embedded file:

$ pdfattach invoice.pdf readme.txt invoice-with-readme.pdf
$ printf 'pdfattach exit status: %s\n' "$?"
pdfattach exit status: 0

A successful run prints nothing; status 0 just means it completed. The input PDF stays in place, and invoice-with-readme.pdf is the new document.

Checkpoint

The output should be a PDF with a different size from the input.

$ file invoice.pdf invoice-with-readme.pdf
invoice.pdf:                 PDF document, version 1.7
invoice-with-readme.pdf:     PDF document, version 1.7
$ ls -l invoice.pdf invoice-with-readme.pdf

Exact file wording and byte counts vary, but both paths should exist and the output should still register as a PDF.

3. List the embedded file

Check the result with Poppler's companion pdfdetach utility instead of opening the attachment:

$ pdfdetach -list invoice-with-readme.pdf
1 embedded files
1: readme.txt

The attachment name comes from the file you passed, not from the output filename. Need a particular name? Rename or copy the source file first, then attach that path. A successful exit status is not proof the intended file got embedded: check the list.

4. Protect an existing output

pdfattach refuses to replace an output PDF that already exists, a useful safety boundary. Repeating the earlier command is not an update operation:

$ pdfattach invoice.pdf readme.txt invoice-with-readme.pdf
File invoice-with-readme.pdf already exists.
$ printf 'pdfattach exit status: %s\n' "$?"
pdfattach exit status: 3

The manual assigns status 3 to an existing output file. Pick another destination, or remove the old one only once you have checked it is disposable. Deleting a PDF is irreversible without a backup, so do not reach for a broad wildcard such as rm *.pdf as a quick fix.

A safer pattern: write to a clearly temporary name, inspect it, then move it into place.

$ pdfattach invoice.pdf readme.txt invoice-with-readme.pdf.new
$ pdfdetach -list invoice-with-readme.pdf.new
1 embedded files
1: readme.txt
$ mv invoice-with-readme.pdf.new invoice-with-readme.pdf

The final mv replaces the old destination only after the new PDF exists and has been inspected. If the attach command fails, leave the original output alone and remove the .new file once you have confirmed it is incomplete.

5. Replace an attachment deliberately

Use -replace when the input PDF already has an embedded file with the same name and you want the new file to take its place. It still writes a separate output PDF:

$ pdfattach -replace invoice-with-readme.pdf updated-readme.txt invoice-updated.pdf
$ printf 'pdfattach exit status: %s\n' "$?"
pdfattach exit status: 0
$ pdfdetach -list invoice-updated.pdf
1 embedded files
1: updated-readme.txt

-replace is about a name collision inside the PDF, not the output path: the output path must still be new, so use a fresh filename or the temporary-output pattern above.

Be precise about the name. An existing attachment called readme.txt and a replacement source called updated-readme.txt are different names, so the command may add a second attachment rather than replace the first. Rename the replacement source to the exact embedded name when the goal is substitution, then verify the list.

6. Diagnose failures without changing state

Start from the documented exit statuses:

  • 1: the input PDF could not be opened. Check its path and permissions.
  • 2: the file to attach could not be opened. Check that path and permissions.
  • 3: the output already exists, or an attachment with the same name already exists without -replace.
  • 5: saving the output failed. Check free space, the destination directory and its permissions.

Capture the status immediately if a script needs to report the reason:

pdfattach "$input_pdf" "$attachment" "$output_pdf"
status=$?
if [ "$status" -ne 0 ]; then
    printf 'pdfattach failed with status %s\n' "$status" >&2
    exit "$status"
fi
pdfdetach -list "$output_pdf"

Do not run the attach step as root merely because a path failed. Check test -r for both inputs and test -w for the destination directory first: elevated privileges can create a result your normal user cannot later update or inspect.

Done means

  • Version confirmed: the installed Poppler version and the three positional arguments are understood.
  • Output written: a new PDF was written with status 0.
  • Attachment verified: pdfdetach -list shows the expected embedded filename.
  • Existing output preserved: nothing got overwritten accidentally.
  • -replace used deliberately: only for a genuine same-name update, always with a new output path.