Print Reliably from the Shell with lpr

Half of print tickets are really wrong-printer tickets, and lpr's defaults make that easy. Let the default destination pick itself and the job lands somewhere you did not expect. This guide gets you submitting a file explicitly, setting copies and duplex, and separating a scheduler problem from a printer problem. Examples match lpr from cups-bsd 2.4.7-1.2ubuntu7.14, CUPS 2.4 syntax throughout.

Give it fifteen minutes, plus whatever the printer itself takes. You need a shell, a readable file, and a working CUPS server and destination. Printing needs no elevated privileges; do not reach for sudo just because a printer is unknown or the scheduler is stopped.

1. Check the command and printer state first

Start with checks that cannot submit anything or change configuration:

$ command -v lpr
/usr/bin/lpr
$ dpkg-query -W -f='${Package} ${Version}\n' cups-bsd
cups-bsd 2.4.7-1.2ubuntu7.14
$ lpstat -p -d

That last command lists available printers and, if one is set, the system default. Output is host-specific. If it says the scheduler is not running, get an administrator to restore CUPS before you try to print anything; starting a service is an administrative change, not part of this guide.

Checkpoint: Write down the exact destination name you plan to use. Treat it as data you looked up, not a guess based on the label stuck to the printer.

2. Name the destination, do not trust the default

Pass -P plus a destination name whenever more than one printer exists, or a job must not land on the default by accident:

$ lpr -P PRINTER_NAME /path/to/report.pdf

Replace both placeholders before you hit enter. A successful submission usually returns silently; a non-zero exit means the client could not submit it at all. Neither outcome proves paper actually came out.

Skip -P and CUPS checks LPDEST, then PRINTER, then whatever lpoptions set, then whatever lpadmin set. That chain is exactly why the printer in your desktop panel is not always the one your shell will actually use:

$ printf 'LPDEST=%s PRINTER=%s\n' "${LPDEST-}" "${PRINTER-}"
LPDEST=PRINTER=

Both blank only tells you those variables are unset. It does not prove there is no CUPS default at all.

3. Submit something small first

Pick a document you can afford to reprint, and check it before you submit:

$ test -r /path/to/report.pdf && echo 'input is readable'
input is readable
$ lpr -P PRINTER_NAME /path/to/report.pdf
$ printf 'lpr exit status: %s\n' "$?"
lpr exit status: 0

Status 0 only means lpr accepted the submission. It says nothing about power, paper or whether the printer can render that file. If the page never appears, check the queue through your normal CUPS tools.

Piping input instead of naming a file works too:

$ printf 'A short test page\n' | lpr -P PRINTER_NAME

Do not pipe an unbounded stream into this. lpr will keep reading for as long as the producer keeps writing.

4. Set copies, paper and duplex explicitly

Each job setting gets its own -o. Two copies, A4, double-sided on the long edge:

$ lpr -P PRINTER_NAME -# 2 \
    -o media=a4 \
    -o sides=two-sided-long-edge \
    /path/to/report.pdf

Supported sizes and options vary by printer, so check what the destination actually advertises before scripting a batch job. A compact example for slides:

$ lpr -P PRINTER_NAME -o number-up=2 /path/to/slides.pdf

5. Name or hold a job on purpose

Give the job a readable title with -T (-C and -J do the same thing):

$ lpr -P PRINTER_NAME -T 'Finance report - review copy' /path/to/report.pdf

-q holds the job instead of printing it, handy when you need several jobs queued before releasing them together through your normal queue tools. A held job is not a failed submission, it is waiting on purpose.

-E forces encryption to the server, but only protects the transport, and only if the server's certificate or auth setup actually supports it. It does not vet the document and does not replace checking the destination.

Common traps

6. Diagnose before you escalate

If a submission fails, repeat the read-only checks first: file readable, destination spelled correctly, scheduler actually running. Then strip options back one at a time, starting from destination plus file alone, adding layout options back in. That isolates a bad destination from an unsupported printer option fast.

A missing default is not fixed by running lpr as root. Fix the intended default through proper CUPS administration, then re-verify from an ordinary shell. If the document is confidential, check the destination and its retention policy before submitting: a printer queue can expose job names, usernames and document metadata to other administrators.

Done means