Merge PDFs from the Command Line

No GUI, no uploads, no problem. Just Ghostscript and a one-liner.

terminal
pdf
ghostscript
Author

James Balamuta

Published

March 19, 2026

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 ghostscript

Install via Chocolatey:

choco install ghostscript

Or 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 ghostscript

Verify the installation by checking the version (gswin64c on Windows):

gs --version

Merging 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 *.pdf

If 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.