Networking#

Zsh itself doesn’t speak the network in the general case; it orchestrates programs that do. What it adds over bash is the zsh/net/tcp and zsh/net/socket modules, which expose ztcp and zsocket builtins for direct kernel-level socket work without spawning nc. The toolkit otherwise is the same coreutils + well-known network utilities.

HTTP#

$ curl -fsSL https://example.com/
$ curl -I https://example.com/
$ curl -X POST -H 'content-type: application/json' \
     -d '{"a":1}' https://api.example.com/v1/items
$ curl -fsS --retry 3 --retry-connrefused -o file.tgz \
     https://example.com/file.tgz

$ wget -q -O- https://example.com/
$ wget -nc https://example.com/file.tgz

Common flags worth memorizing.

  • -f (curl), fail on HTTP errors. Use everywhere; without it scripts silently miss 4xx / 5xx.

  • -s, silent. Often paired with -S to keep error messages.

  • -L, follow redirects.

  • --max-time, --connect-timeout, always set both in scripts.

JSON#

$ curl -fsS https://api.example.com/users/1 | jq '.name'
$ jq -r '.items[].id' input.json
$ curl -fsS -X POST https://api.example.com/items \
     --data-raw "$(jq -n --arg n "$NAME" '{name:$n}')"

TCP / UDP#

Zsh has two ways to reach a socket. /dev/tcp/host/port and /dev/udp/host/port pseudo-paths work (same as bash) for quick probes. The zsh/net/tcp module attaches the ztcp builtin for more control: persistent connections, line reads, server sockets.

Pseudo-path probes.

$ if (print -- > /dev/tcp/host/22) 2>/dev/null; then
  $ print -- "open"
$ fi

$ exec 3<>/dev/tcp/example.com/80
$ printf 'GET / HTTP/1.0\r\nHost: example.com\r\n\r\n' >&3
$ cat <&3
$ exec 3<&-

ztcp direct socket work.

$ zmodload zsh/net/tcp
$ ztcp example.com 80                          # opens fd in $REPLY
$ fd=$REPLY
$ print -- "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" >&$fd
$ while read -r -u $fd line; do print -- "$line"; done
$ ztcp -c $fd                                  # close

$ ztcp -l 4444                                 # listen on 4444
$ ztcp -a $REPLY                               # accept incoming

For real interactive work, use netcat.

$ nc -zv host 22
$ nc -u -zv host 53
$ nc -l -p 4444

DNS#

$ getent hosts example.com
$ dig +short example.com
$ dig +short example.com AAAA
$ dig @8.8.8.8 example.com
$ host example.com

SSH and File Transfer#

$ ssh user@host 'systemctl status nginx'
$ scp file user@host:/path/
$ rsync -aP src/ user@host:/path/
$ rsync -aP --delete src/ user@host:/path/

Fan out to a host list (zsh array form).

$ hosts=(web01 web02 db01 cache01)
$ for h in $hosts; do
  $ ssh -o ConnectTimeout=3 "$h" 'uptime'
$ done

In parallel with & and wait.

$ for h in $hosts; do
  $ ssh -o ConnectTimeout=3 "$h" 'uptime' &
$ done
$ wait

Authentication Tokens#

Don’t put tokens on the command line; they leak through ps, history, and logs.

$ curl -H "Authorization: Bearer $(<~/.config/myapp/token)" ...
$ curl -H "Authorization: Bearer $TOKEN" ...
$ curl --netrc-file ~/.netrc ...

The $(<file) form is zsh / bash shorthand for $(cat file) without the cat fork.

Diagnostics#

$ ping -c 3 host
$ traceroute host
$ mtr host
$ ss -tulpn
$ tcpdump -ni any port 443
$ tshark -i any -f 'port 443'

For “is this URL up and what does it look like”.

$ curl -o /dev/null -s -w 'http=%{http_code} time=%{time_total}\n' https://example.com/

References#

  • man 1 zshmodules (zsh/net/tcp, zsh/net/socket).

  • man 1 curl, man 1 ssh, man 1 dig, man 1 nc.

  • I/O and Pipelines for the redirection and process-substitution patterns that pair with network commands.

  • Common Tasks for the OS-level Common Tasks list these commands live inside.

  • Coreutils for the surrounding text- manipulation toolkit.