Attach a File to a PDF Safely with pdfattach
You will add a file to an existing PDF, confirm that the attachment is present, and handle an existing attachment without silently overwriting your output. This guide uses pdfattach from Poppler 24.02.0, provided here by poppler-utils. Allow about ten minutes if you already have the PDF and file ready.
The route
Jump straight to the step you need, or tick off Done means at the end.
The workflow only creates new output files. It does not change the input PDF or the file being attached. You need a readable input PDF, a readable attachment, and a directory where you can write the result. 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 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 path is a new PDF, not an output directory.
2. Attach a file to a new PDF
Choose 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 normally prints no progress message. Status 0 means the command completed without an error. The input PDF remains in place, while invoice-with-readme.pdf is the new document.
Checkpoint: make sure the output is a PDF and has 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
The exact file wording and byte counts vary. The important checks are that both paths exist and the output can still be recognised as a PDF.
3. List the embedded file
Use Poppler's companion pdfdetach utility to inspect the result without opening the attachment:
$ pdfdetach -list invoice-with-readme.pdf
1 embedded files
1: readme.txt
The attachment name is taken from the file you passed, not from the PDF output name. If you need a particular name, rename or copy the source file first, then attach that path. Do not assume that a successful exit status proves the intended file was embedded; check the list.
4. Protect an existing output
pdfattach refuses to replace an output PDF that already exists. That is 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 output only after checking that it is disposable. Deleting a PDF is irreversible unless you have a backup, so do not use a broad wildcard such as rm *.pdf as a quick fix.
A safer replacement pattern is to write to a clearly temporary name, inspect it, and 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 has been created and inspected. If the attach command fails, leave the original output untouched and remove the .new file when you have confirmed it is incomplete.
5. Replace an attachment deliberately
Use -replace when the input PDF already contains 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
The option is about an attachment name collision inside the PDF. It does not permit the output path to exist. The output path must still be new, so use a new filename or the temporary-output pattern above.
Be precise about the name. If the existing attachment is called readme.txt but the replacement source is called updated-readme.txt, those names are different. The command may add a second attachment rather than replace the first. Rename the replacement source to the exact embedded name when your goal is substitution, then verify the list.
6. Diagnose failures without changing state
The documented exit statuses identify the first useful place to look:
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. First check test -r for both inputs and test -w for the destination directory. Elevated privileges can create a result that your normal user cannot later update or inspect.
Done means
- The installed Poppler version and the three positional arguments are understood.
- A new PDF was written with status 0.
pdfdetach -listshows the expected embedded filename.- An existing output was preserved rather than overwritten accidentally.
-replacewas used only for a deliberate same-name attachment update, with a new output path.