2026-09-03
Everyone knows bc. Almost nobody remembers that bc was originally a front-end that compiled to dc bytecode — the "d" and "c" both stand for calculator, and dc is the older one. It shipped in Unix v1. It predates C. And it's still sitting in /usr/bin on every Linux and BSD box you touch, quietly guaranteed by POSIX.
Under the hood it's a reverse Polish notation calculator with arbitrary precision arithmetic, 256 named registers (each of which is itself a stack), macros, and conditional execution. Which is a fancy way of saying dc is Turing complete — the smallest programmable language POSIX guarantees on your system.
Push operands, then the operator. p prints the top of stack without popping. k sets decimal precision. i and o set input and output base.
$ echo '2 3 + p' | dc
5
$ echo '20 k 22 7 / p' | dc
3.14285714285714285714
$ echo '2 1000 ^ p' | dc
10715086071862673209484250490600018105614... # 302 digits, no bignum library needed
Every developer eventually needs to turn 0xDEADBEEF into decimal, or a decimal into binary. Most reach for Python. dc does it in one pipe:
$ echo '16 i DEADBEEF p' | dc
3735928559
$ echo '16 o 3735928559 p' | dc
DEADBEEF
$ echo '2 o 255 p' | dc
11111111
Set the input base first (16 i). After you change it, following digits are parsed in the new base — including any digits meant to set the output base afterward. That subtlety is where every first-time user eats it.
Anything between [ and ] is a string. Store in register S with sS, load with lS, execute with x.
# Define "square" as dup-multiply, apply to 7
$ dc -e '[d*]sS 7 lSx p'
49
# Compose it: fourth power = square of square
$ dc -e '[d*]sS 3 lSx lSx p'
81
Conditional operators (=r, <r, >r) pop two values and run register r's macro if the relation holds. Combine that with a macro that reloads itself and you have loops. That is genuinely all you need to write real programs — Rosetta Code has full dc implementations of factorial, Fibonacci, primality, and RPN evaluators, most under 100 bytes.
awk and tee and it Just Works.dc invocation runs an order of magnitude faster than python -c. Inside a tight shell loop that matters.from decimal import, no --mathlib flag. 2 10000 ^ just works and prints all 3011 digits.The one real gotcha is that RPN gets unforgiving once expressions nest. Past three operators, break into newlines and use # comments (GNU extension) or write the intent above the invocation. Otherwise you will be debugging stack order at 2am, and that is not what a wizard-tier tool should be reduced to.
dc is the smallest Turing-complete language POSIX guarantees on your system — reach for it when you want arbitrary precision arithmetic or base conversion in a pipeline without paying the startup cost of a real interpreter.
