Extract Embedded Files from PDFs with pdfdetach
Someone emails a PDF and mentions a spreadsheet is buried inside it: pdfdetach lists and pulls out attachments, no graphical viewer needed. It uses Poppler 24.02.0, installed here as poppler-utils 24.02.0-1ubuntu9.9. Allow about ten minutes once you have the PDF and know where the extracted files should go.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need a readable PDF, a shell and the poppler-utils package. These commands normally run as your ordinary user. Do not reach for sudo merely because the PDF came from someone else; copy it to a working directory you own instead if you need to read a protected location.
1. Check the installed command
Confirm which executable will run and record its version. This is a read-only checkpoint:
$ command -v pdfdetach
/usr/bin/pdfdetach
$ pdfdetach -v
pdfdetach version 24.02.0
$ dpkg-query -W -f='${Package} ${Version}\n' poppler-utils
poppler-utils 24.02.0-1ubuntu9.9
The local manual page describes itself as version 3.03, while the installed binary reports Poppler 24.02.0. Use the executable's version when comparing behaviour across machines; the option names below appear in both the manual and the installed help output.
2. List the embedded files
Start with a list. Swap in the real file, and keep the path quoted if it contains spaces:
$ pdfdetach -list '/path/to/document.pdf'
1 embedded file
1: notes.txt
2: source-data.csv
Names and formatting are document-dependent, so treat the numbers as the useful part: -save selects by number, -savefile selects by the embedded file name. Nothing gets extracted at this step.
Checkpoint
Repeat the list with an explicit status check, run immediately after so a later command cannot overwrite the status you are checking:
$ pdfdetach -list '/path/to/document.pdf'
$ printf 'exit status: %s\n' "$?"
exit status: 0
3. Extract one attachment by number
Use the number shown by -list. By default, -save writes to the current directory using the embedded file name:
$ mkdir -p /tmp/pdfdetach-work
$ cd /tmp/pdfdetach-work
$ pdfdetach -save 1 '/path/to/document.pdf'
$ ls -l -- notes.txt
-rw-r--r-- 1 alice alice 1842 Sep 25 12:00 notes.txt
Size, owner and timestamp will differ on your machine; the useful check is that the expected file exists and is non-empty. For a text attachment, inspect it without executing anything:
$ file -- notes.txt
notes.txt: ASCII text
$ sed -n '1,12p' -- notes.txt
- Do not trust a familiar name or extension. Treat extracted files as untrusted input.
- Scan before opening or running. Use your usual tools first.
4. Choose a different output name
Use -o with -save for a controlled destination name, which also makes the output easier to identify in an automated job:
$ pdfdetach -save 2 -o '/tmp/pdfdetach-work/data.csv' '/path/to/document.pdf'
$ test -s '/tmp/pdfdetach-work/data.csv'
$ printf 'extracted: %s\n' "$?"
extracted: 0
With a single-file save, -o names a file, not a directory. Do not confuse the number with a shell positional argument either: -save 2 means attachment number 2, not a file called 2.
Warning
Choose a new destination when an existing file matters. An output command can replace whatever sits at the path you give it, and pdfdetach has no undo. Restore an overwritten file from backup or snapshot.
5. Extract every attachment into a clean directory
-saveall writes every embedded file using the names -list reported. Pass a directory with -o:
$ mkdir -p /tmp/pdfdetach-work/all
$ pdfdetach -saveall -o /tmp/pdfdetach-work/all '/path/to/document.pdf'
$ find /tmp/pdfdetach-work/all -maxdepth 1 -type f -printf '%f\n' | sort
notes.txt
source-data.csv
Omitting -o defaults to the current directory, which is easy to get wrong. A clean, disposable directory keeps extracted names away from unrelated files. Names come from the PDF itself, so inspect the directory afterwards rather than blindly piping every result into another program.
There is no elevated-privilege step here. Fix an unwritable destination's path or ownership deliberately rather than running the whole extraction as root.
6. Select by embedded file name
If a PDF gets regenerated and attachment numbers may shift, -savefile selects by the name -list printed:
$ pdfdetach -savefile 'source-data.csv' \
-o '/tmp/pdfdetach-work/source-data.csv' \
'/path/to/document.pdf'
$ file -- '/tmp/pdfdetach-work/source-data.csv'
Use the embedded name exactly as listed, including case and punctuation. A name that looks like a path is still input supplied by the document, so prefer an explicit -o path and a directory you have already checked. If the name is ambiguous, or the command cannot find it, go back to -list and copy the displayed name rather than guessing.
7. Handle passwords and failures
For an encrypted PDF, -upw supplies the user password and -opw supplies the owner password:
$ pdfdetach -list -upw 'USER_PASSWORD' '/path/to/encrypted.pdf'
$ printf 'exit status: %s\n' "$?"
exit status: 0
Security warning
The local manual says an owner password bypasses all PDF security restrictions, so treat -opw as security-sensitive and use it only when authorised. Never paste a real password into a shared terminal, shell history or a script, and a password does not make an untrusted attachment safe.
The documented exit statuses:
- 0: no error.
- 1: the PDF could not be opened.
- 2: an output file could not be opened.
- 3: a PDF permission error occurred.
- 99: another error occurred.
A missing input, for example, is a path problem, not a reason to reach for sudo:
$ pdfdetach -list /tmp/does-not-exist.pdf
I/O Error: Couldn't open file '/tmp/does-not-exist.pdf': No such file or directory.
$ printf 'exit status: %s\n' "$?"
exit status: 1
Check the path with ls -l, readability with test -r, and the destination with test -w. Keep the original PDF until the extracted files have passed inspection.
Done means
- List checked:
pdfdetach -listshowed which attachments were present and returned status 0. - Right file selected: by its listed number or exact name.
- Output placed correctly: single-file output used an explicit destination, all-file output used a clean directory.
- Extracted files inspected: sensible sizes and types, treated as untrusted input.
- Failures classified: by exit status, with the original PDF left untouched.