If you’ve ever had to assemble a job application package, a grant submission, or any other multi-document PDF, you’ve probably reached for a GUI tool or an online service to stitch the files together. I wanted something I could script and re-run as I revised individual documents. Enter Ghostscript, a venerable, open-source tool that handles this beautifully from the command line.
Installing Ghostscript
Ghostscript is available on all major platforms. Pick your OS below:
Install via Homebrew:
brew install ghostscriptInstall via Chocolatey:
choco install ghostscriptOr download the installer directly from the Ghostscript releases page.
On Windows, the executable is called gswin64c (or gswin32c for 32-bit) rather than gs.
Install via your distribution’s package manager:
# Debian / Ubuntu
sudo apt install ghostscript
# Fedora
sudo dnf install ghostscript
# Arch
sudo pacman -S ghostscriptVerify the installation by checking the version (gswin64c on Windows):
gs --versionMerging PDFs
The core command is straightforward. Pass in the input files in the order you want them and Ghostscript writes them out as a single PDF:
gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite \
-sOutputFile=merged-output.pdf \
"first-document.pdf" \
"second-document.pdf" \
"third-document.pdf"gswin64c -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite `
"-sOutputFile=merged-output.pdf" `
"first-document.pdf" `
"second-document.pdf" `
"third-document.pdf"Here’s what each flag does:
| Flag | Purpose |
|---|---|
-dBATCH |
Exit after processing (no interactive prompt) |
-dNOPAUSE |
Don’t pause between pages |
-q |
Quiet mode (suppress status messages) |
-sDEVICE=pdfwrite |
Output format is PDF |
-sOutputFile= |
Path for the merged output file |
The order of the input files determines page order in the final PDF. Put your most important document first!
Wrapping It in a Reusable Script
If you find yourself re-running the merge every time you revise a document, it helps to wrap the command in a reusable script. Both versions below use an -o flag for the output filename (defaulting to merged-output.pdf) and accept input files as remaining arguments, including globs like *.pdf.
#!/bin/bash
# merge-pdfs.sh: Merge multiple PDFs into one using Ghostscript.
# Usage: ./merge-pdfs.sh [-o output.pdf] input1.pdf [input2.pdf ...]
# ./merge-pdfs.sh [-o output.pdf] *.pdf
set -euo pipefail
OUTPUT="merged-output.pdf"
# Parse optional -o flag
if [ "${1:-}" = "-o" ]; then
OUTPUT="$2"
shift 2
fi
if [ "$#" -lt 1 ]; then
echo "Usage: $0 [-o output.pdf] <input1.pdf> [input2.pdf ...]"
exit 1
fi
# Filter out the output file from the input list so that
# globs like *.pdf don't accidentally include it.
INPUTS=()
for f in "$@"; do
[ "$(basename "$f")" != "$(basename "$OUTPUT")" ] && INPUTS+=("$f")
done
if [ "${#INPUTS[@]}" -eq 0 ]; then
echo "Error: No input PDFs found (after excluding the output file)."
exit 1
fi
gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite \
-sOutputFile="$OUTPUT" \
"${INPUTS[@]}"
echo "Merged ${#INPUTS[@]} PDF(s) into: $OUTPUT"Make it executable and run it:
chmod +x merge-pdfs.sh
# Merge specific files in a specific order
./merge-pdfs.sh -o application-package.pdf \
cover-letter.pdf cv.pdf research-statement.pdf
# Merge all PDFs in the current directory
./merge-pdfs.sh -o combined.pdf *.pdf
# Use the default output name (merged-output.pdf)
./merge-pdfs.sh *.pdf# merge-pdfs.ps1: Merge multiple PDFs into one using Ghostscript.
# Usage: .\merge-pdfs.ps1 [-o output.pdf] input1.pdf [input2.pdf ...]
# .\merge-pdfs.ps1 [-o output.pdf] *.pdf
param(
[Alias("o")]
[string]$Output = "merged-output.pdf",
[Parameter(Mandatory, ValueFromRemainingArguments)]
[string[]]$InputFiles
)
$ErrorActionPreference = "Stop"
# Resolve globs and flatten into a single list
$Resolved = $InputFiles | ForEach-Object { Resolve-Path $_ } |
Select-Object -ExpandProperty Path
# Filter out the output file so *.pdf doesn't feed it back in
$OutputFull = (Resolve-Path $Output -ErrorAction SilentlyContinue).Path
$Resolved = $Resolved | Where-Object { $_ -ne $OutputFull }
if ($Resolved.Count -eq 0) {
Write-Error "No input PDFs found (after excluding the output file)."
exit 1
}
& gswin64c -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite `
"-sOutputFile=$Output" @Resolved
Write-Host "Merged $($Resolved.Count) PDF(s) into: $Output"Run it from PowerShell:
# Merge specific files in a specific order
.\merge-pdfs.ps1 -o application-package.pdf `
cover-letter.pdf cv.pdf research-statement.pdf
# Merge all PDFs in the current directory
.\merge-pdfs.ps1 -o combined.pdf *.pdf
# Use the default output name (merged-output.pdf)
.\merge-pdfs.ps1 *.pdfIf you installed the 32-bit version of Ghostscript, replace gswin64c with gswin32c in the script.
When using a glob like *.pdf, the shell expands it alphabetically. If page order matters, either name your files with a numeric prefix (e.g. 01-cover-letter.pdf, 02-cv.pdf) or list them explicitly.
Both scripts automatically exclude the output file from the input list, so you don’t have to worry about *.pdf feeding the output back into itself.
Fin
That’s it! A quick, scriptable way to merge PDFs without leaving the terminal or reaching for a heavy GUI application. Ghostscript is widely available across platforms, fast, and handles the job reliably. Next time you need to assemble a multi-document PDF, give it a try.