Netcat Cheatsheet
Basics and Flags
Use this Netcat reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Which netcat do you have
"netcat" is three unrelated programs plus a rewrite, and their flags differ in ways that break copy-pasted commands. Check first.
nc -h 2>&1 | head -3 ncat --version readlink -f "$(which nc)" # Linux, often a symlink into alternatives
| Variant | Binary | Ships on | Tell |
|---|---|---|---|
| OpenBSD nc | nc | Debian/Ubuntu (netcat-openbsd), Alpine, *BSD | Usage line lists -N, -U, -X, -Z |
| macOS nc | nc | macOS, Apple's fork of OpenBSD nc | Usage line has --apple-* options |
| netcat-traditional | nc, nc.traditional | Debian (netcat-traditional) | Prints [v1.10-…], has -e |
| GNU netcat | nc, netcat | Some distros (netcat 0.7.x) | Long options, --exec, --tunnel |
| Ncat | ncat | Nmap package, everywhere | Ncat 7.x ( https://nmap.org/ncat ) |
| BusyBox nc | nc | Containers, embedded | Tiny usage, -e present, little else |
Ncat is the one to prefer when you have a choice. It is maintained,
portable, and adds TLS, access control, and proxying that the others lack.
nc in a scratch container is usually BusyBox with almost no options.
Flag compatibility table
The flags that matter, and where they exist. A dash means absent.
| Purpose | OpenBSD nc | macOS nc | traditional | GNU netcat | Ncat |
|---|---|---|---|---|---|
| Listen | -l | -l | -l | -l | -l |
| Keep listening | -k | -k | — | — | -k |
| UDP | -u | -u | -u | -u | -u |
| No DNS | -n | -n | -n | -n | -n |
| Verbose | -v | -v | -v | -v | -v |
| Connect / read timeout | -w n | -w n | -w n | -w n | -w n |
| Zero-I/O scan | -z | -z | -z | -z | -z |
| Source port | -p | -p | -p | -p | -p |
| Source address | -s | -s | -s | -s | -s |
| Randomize ports | -r | -r | -r | -r | — |
| Delay between lines | -i n | -i n | -i n | -i n | -d n |
| Telnet negotiation | -t | -t | -t | -T | -t |
| CRLF line endings | -C | -c | — | — | -C |
| Execute a program | — | — | -e | -e | -e / -c |
| Shutdown write on EOF | -N | — | — | — | --send-only |
| Wait n secs after EOF | -q n | — | — | — | -q n |
| Unix socket | -U | -U | — | — | -U |
| SOCKS/HTTP proxy | -x, -X | -x, -X | — | — | --proxy |
| TLS | — | — | — | — | --ssl |
| IPv4 / IPv6 only | -4 / -6 | -4 / -6 | — | — | -4 / -6 |
| Hex dump the session | — | — | -o file | -o file | -x file |
The three that cause the most confusion:
- -e does not exist in OpenBSD or macOS nc. It was removed
deliberately. Recipes using nc -e come from netcat-traditional or
BusyBox. Use ncat -e or ncat -c.
- -c means two different things. On macOS nc it sends CRLF. On Ncat it
runs a command through /bin/sh. Pasting nc -c expecting Ncat behavior
silently does nothing useful.
- -t versus -T. GNU netcat uses -t for TCP and -T for telnet
negotiation, the reverse of everyone else.
Two modes, one binary
Everything netcat does is one of two things.
# Client: connect out to host:port, wire stdin/stdout to the socket nc example.com 80 # Server: bind a port, wait for one connection, wire stdin/stdout to it nc -l 8080
Between those endpoints netcat is a plain pipe. It adds no framing, no protocol, no encoding. Whatever bytes you type go out, whatever comes back lands on stdout. That is the whole design, and it is why netcat works for any text protocol without knowing what it is.
Flags you will use every session
nc -v -n -w 5 10.0.0.5 443 # verbose, no DNS, 5s timeout nc -l -k -p 8080 # listener that survives disconnects nc -u -l 5514 # UDP listener nc -z -v 10.0.0.5 22 # just report open or closed
| Flag | Why you want it |
|---|---|
-v | Otherwise a failed connection is completely silent |
-n | Skips DNS, so a hang is the network and not the resolver |
-w 5 | Without it a filtered port hangs for the OS default, often 2 min |
-k | Listener accepts a second connection instead of exiting |
-z | Connect, report, close. No data transferred |
-u | UDP. Changes the semantics substantially, see the UDP topic |
-v is close to mandatory. Plain nc host port on a closed port exits with
status 1 and prints nothing at all.
Exit status
nc -z -w 3 10.0.0.5 443 && echo open || echo "closed or filtered"
| Status | Meaning |
|---|---|
| 0 | Connected successfully, or the transfer completed |
| 1 | Connection refused, timed out, or otherwise failed |
| 2 | Usage or argument error (varies by variant) |
-z plus the exit status is the whole reason netcat shows up in health
checks and container entrypoints. But 0 only means the TCP handshake
completed, and says nothing about whether the application behind the port
is healthy.
The port-open one-liner without netcat
Worth knowing, because minimal images often have no nc at all.
# bash, no external binary timeout 3 bash -c 'cat < /dev/null > /dev/tcp/10.0.0.5/443' \ && echo open || echo closed # Read a banner the same way exec 3<>/dev/tcp/example.com/80 printf 'GET / HTTP/1.0\r\n\r\n' >&3 cat <&3 exec 3<&-
/dev/tcp/host/port is a bash feature, not a real device, so it is absent
in sh, dash, and busybox ash. TCP only, no UDP, no listening.