Home / Alt manpages / proc_pid_cmdline(5)

  • proc_pid_cmdline(5)
  • File format
  • linux

Read a Linux Process Command Line Without Losing Its Boundaries

You will inspect a live process through /proc/PID/cmdline, turn its null-separated arguments into readable output, and keep the limitations of that view visible. The examples use the proc_pid_cmdline(5) page from Debian's manpages package version 6.7-2, whose page identifies Linux man-pages 6.7.

Allow about ten minutes. You need a shell and a process ID that you are allowed to inspect. The commands are read-only and normally need no elevated privileges. Do not use the displayed command line as proof of identity, authorisation or what a process is really executing: the manpage explicitly allows a process to change the memory represented by this file.

1. Choose a live process ID

Start with the shell that is running the check. $$ expands to the current shell's process ID, so it avoids guessing a service PID:

$ printf 'shell PID: %s\n' "$$"
shell PID: 12345
$ test -r "/proc/$$/cmdline" && echo 'cmdline is readable'
cmdline is readable

Your PID will differ. If you are checking another process, replace PID below with digits copied from a trusted local source such as a process supervisor or ps. Do not paste an arbitrary path into a script that later runs with elevated privileges.

Checkpoint: confirm that the process still exists immediately before reading it:

$ test -d /proc/PID && echo 'process directory exists'
process directory exists

A process can exit between this check and the read. That is a normal race, not a reason to retry forever.

2. See the raw argument representation

For a well-behaved running process, the file contains argument strings separated by null bytes, written as \0, with another null byte after the final argument. A normal line printer will not display those separators usefully. Inspect the bytes instead:

$ head -c 200 /proc/$$/cmdline | od -An -t x1c
  62  61  73  68  00  2d  69  00  00
   b   a   s   h  \0   -   i  \0  \0

The exact bytes depend on how your shell was started. The important boundary is the 00 byte between arguments. The final output can contain a trailing null as well. head -c is only a display limit; it does not mean the process has a short command line.

Do not use a command such as cat /proc/PID/cmdline when you need readable argument boundaries. It sends the null bytes directly to the terminal, where they are easy to miss.

3. Convert nulls to newlines for a quick inspection

For an interactive check, replace each null byte with a newline:

$ tr '\0' '\n' < /proc/$$/cmdline
bash
-i

This gives one visible line per argument and is convenient for a human check. It is not a lossless text format. An argument may itself contain a newline, so do not feed this output to a line-oriented parser and assume each line is one safe shell word.

Checkpoint: compare the result with the shell's own view:

$ printf 'pid=%s\n' "$$"
pid=12345
$ tr '\0' '\n' < "/proc/$$/cmdline"
bash
-i

The two commands should identify the same shell invocation, but the exact arguments depend on the terminal, parent process and shell options.

4. Preserve boundaries in a script

If another tool can read null-delimited input, keep the original representation. For example, Bash can read each field without treating spaces inside an argument as separators:

pid=$$
while IFS= read -r -d '' argument; do
    printf 'arg: %s\n' "$argument"
done < "/proc/$pid/cmdline"

This prints the argument text without asking the shell to evaluate it. The double quotes around the path and variable are deliberate. Never turn the result into a command by using eval, unquoted expansion or a shell command substitution.

A process may provide an unusual or empty representation. The manpage describes the null-separated form as the common case, not a permanent format guarantee. If your parser requires a particular layout, treat an empty read or unexpected bytes as an inspection failure and report the PID separately.

5. Handle an empty read correctly

An empty result has more than one explanation. The documented case is a zombie process: /proc/PID/cmdline returns zero characters for a zombie. A process may also disappear during the read, or the path may be unreadable under the host's proc and permission policy.

Check the process state without changing it:

$ ps -o pid=,stat=,comm= -p PID
12345 Z    example
$ test -s /proc/PID/cmdline
$ printf 'read status: %s\n' "$?"
read status: 1

Z indicates a zombie in the ps output. A non-zombie process can still have a short or unusual result, and a vanished PID can make the second command fail. Record which case occurred instead of reporting an empty command line as proof that the process had no arguments.

If the target belongs to another account or is protected by the host's proc configuration, first retry as the same account that owns the diagnostic workflow. Use sudo only when your system's policy requires it and you are authorised to inspect that process. Elevated access changes who can see data; it does not make a stale PID reliable.

6. Treat the value as a requested display

The kernel exposes the process's argument memory through this file, but a process can modify its argv strings after execve. It can also change the memory range used for the file through prctl operations such as PR_SET_MM_ARG_START. The result is therefore best read as the command line the process wants you to see.

That boundary matters in monitoring and incident response. Use /proc/PID/cmdline to display a useful hint, then corroborate important claims with independent evidence such as the executable link, process credentials, open file descriptors and service-manager state. Do not authorise an action solely because a command line contains an expected word.

There is no undo operation for these examples. Reading the file does not change the process, its arguments or its service configuration. If you are collecting output for a report, protect it as potentially sensitive: command lines often contain file names, connection details or other operator-supplied values.

Done means

  • You selected a live PID and checked the target path without guessing a service identity.
  • You know that the ordinary representation is null-separated, with a possible trailing null.
  • You used tr only for human-readable inspection and preserved nulls for parsing.
  • You can distinguish a zombie or vanished process from a genuinely empty-looking display.
  • You treat the value as process-controlled text, not as proof of execution or authorisation.
  • You made no state changes, so there is nothing to undo.