lsns lists every namespace your shell can see, in one read-only pass. It is the first thing to reach for when a container looks isolated in ways you did not expect, and it can also narrow down to the namespaces held by a single process. Nothing here creates, joins, destroys or reconfigures a namespace.
Allow about ten minutes. You need a Linux shell with lsns installed. The normal checks are read-only and do not need sudo. Root access can reveal more of /proc, but it is not a substitute for checking which process or namespace you meant to inspect in the first place.
Start with the executable, version and help text. This matters because util-linux releases add options and columns over time, and the default display is explicitly not a stable interface.
$ command -v lsns
/usr/bin/lsns
$ lsns --version
lsns from util-linux 2.39.3
$ lsns --help
Your paths and version may differ. On this host, the distribution package is util-linux 2.39.3. If another installation appears first in PATH, its version and supported options are the ones that apply. Check every candidate before you rely on anything:
$ type -a lsns
lsns is /usr/bin/lsns
$ dpkg-query -W -f='${Package} ${Version}\n' util-linux
util-linux 2.39.3-9ubuntu6.6
Checkpoint: stop here if the command is missing, or if its version does not match the documentation you are using. Run lsns --help on the actual binary before copying an option into a script.
With no namespace argument, lsns lists the currently accessible namespaces. Each row is a namespace instance, identified by an inode number in the NS column.
$ lsns | head -9
NS TYPE NPROCS PID USER COMMAND
4026531834 time 87 1998 alice tmux -u -2 ...
4026531835 cgroup 87 1998 alice tmux -u -2 ...
4026531836 pid 87 1998 alice tmux -u -2 ...
4026531837 user 132 1998 alice tmux -u -2 ...
4026531838 uts 87 1998 alice tmux -u -2 ...
4026531839 ipc 87 1998 alice tmux -u -2 ...
4026531840 net 87 1998 alice tmux -u -2 ...
4026531841 mnt 87 1998 alice tmux -u -2 ...
The exact rows are host-specific. The namespace types supported by this release are mnt, net, ipc, user, pid, uts, cgroup and time. NPROCS is a count, while PID is the lowest process ID found in that namespace. Do not treat the displayed command as a unique namespace name.
Two defaults cause avoidable confusion: text can be truncated to fit the terminal, and the default columns or layout can change between releases. Fine for a glance. Not fine for a report or a script, where you should pick the layout and columns yourself.
Use --list and --output when you want one row per namespace with a small, explicit set of fields:
$ lsns --list --output NS,TYPE,PATH,COMMAND | head -8
NS TYPE PATH COMMAND
4026531834 time /proc/1998/ns/time tmux -u -2 ...
4026531835 cgroup /proc/1998/ns/cgroup tmux -u -2 ...
4026531836 pid /proc/1998/ns/pid tmux -u -2 ...
4026531837 user /proc/1998/ns/user tmux -u -2 ...
4026531838 uts /proc/1998/ns/uts tmux -u -2 ...
4026531839 ipc /proc/1998/ns/ipc tmux -u -2 ...
4026531840 net /proc/1998/ns/net tmux -u -2 ...
Ask the installed command for the complete column vocabulary with lsns --list-columns. Useful fields include NS, TYPE, PATH, NPROCS, PID, USER, COMMAND, NSFS, PNS and ONS. A column list is not a guarantee every value will be present: a namespace can be visible while its process information is limited.
If truncation would hide evidence, add --notruncate. If you need machine-readable data, --json is available, but still choose the columns you depend on and test the exact util-linux release in your environment.
Use --task with a PID when the question is about one process rather than the whole host. The shell variable below supplies the current shell's own PID, so you are not guessing a host-specific number:
$ lsns --task "$$" --list --output NS,TYPE,PATH,COMMAND
NS TYPE PATH COMMAND
4026531834 time /proc/1998/ns/time tmux -u -2 ...
4026531835 cgroup /proc/1998/ns/cgroup tmux -u -2 ...
4026531836 pid /proc/1998/ns/pid tmux -u -2 ...
4026531837 user /proc/1998/ns/user tmux -u -2 ...
4026531838 uts /proc/1998/ns/uts tmux -u -2 ...
4026531839 ipc /proc/1998/ns/ipc tmux -u -2 ...
4026531840 net /proc/1998/ns/net tmux -u -2 ...
Compare the NS values for two processes to see which namespace instances they share. A different process can have the same inode for one type and a different inode for another. That is normal: namespace isolation is per type, not one all-or-nothing switch.
To inspect one type across the host, repeat --type as needed:
$ lsns --type net --list --output NS,TYPE,PATH,NSFS
NS TYPE PATH NSFS
4026531840 net /proc/1998/ns/net /run/docker/netns/default
Network namespace rows can contain multi-line NSFS cells. Add --nowrap when a single-line, comma-separated representation is easier to capture:
$ lsns --type net --nowrap --list --output NS,TYPE,NSFS,PATH
lsns reads directly from /proc. An unprivileged user can therefore see incomplete information, and the current /proc view can itself be shaped by a PID namespace. If a process you expect is absent, confirm the PID and the proc mount you are viewing before doing anything else:
$ test -r /proc/PROCESS_ID/ns/net && echo namespace-link-readable
$ readlink /proc/PROCESS_ID/ns/net
net:[4026531840]
Replace PROCESS_ID with digits from a trusted process listing. Reading these paths is safe. Do not restart a service or alter mounts just because one listing came back shorter than expected. If policy allows it, compare the result with an elevated read-only invocation:
$ sudo lsns --task PROCESS_ID --list --output NS,TYPE,PATH
# enter your normal administrative password only if prompted
Using sudo changes who reads /proc, not what namespaces exist. A difference between the two runs is evidence of a visibility or permission boundary, and should be recorded as such rather than explained away.
Persistent namespaces are another trap. --persistent shows namespaces without processes, created by bind-mounting a /proc/PID/ns/TYPE file to a filesystem path. A namespace held by such a mount may not show up in lsns unless you have a process or accessible mount path tying it to the current /proc view.
The number in NS is an inode number: not a PID, and not a durable name to carry between boots. It is useful for comparing rows within one investigation. Do not build a long-lived inventory that assumes a particular inode will always mean the same isolation boundary.
For a script, avoid parsing the default output. Request a layout and columns explicitly, suppress headings if you like, and handle a non-zero exit status:
$ lsns --list --noheadings --output NS,TYPE,PID
$ status=$?
$ test "$status" -eq 0 || printf 'lsns failed with status %s\n' "$status" >&2
The documented exit statuses are 0 for success, 1 for a general error and 2 when an ioctl is unknown to the kernel. Keep the command's stderr and status in your diagnostics; an empty result on its own is not proof the host has no namespaces.
lsns binary and util-linux version in use.--task and compare namespace inode values.--type, --nowrap, --persistent and explicit columns are useful.