On Linux, sysctl exposes selected kernel parameters through /proc/sys. It can inspect the running state, and an authorized write can change that state without rebooting. A configuration file is a separate instruction to a loader. Confusing these two layers produces a familiar incident: the desired value is on disk, but the kernel is doing something else.
This article covers Linux with procps-ng and systemd. BSD and macOS also have commands named sysctl, but their interfaces and persistence mechanisms are different. A key count collected on macOS does not establish anything about Linux’s procfs tree.
Read the interface you actually have
For ordinary names, kernel.ostype corresponds to /proc/sys/kernel/ostype; procps accepts slash separators too. Names containing literal dots need the documented separator rules, rather than a blind string replacement. Available keys depend on kernel configuration, loaded modules and the execution environment. The table is not a fixed schema across machines or even across one machine’s lifetime.
Normal procps output uses key = value; -n prints only the value. A successful read establishes an observation in the caller’s environment, not a durable policy. Some values change while you inspect them. Read only the keys needed for the diagnosis: even reads are not universally passive. The manual excludes vm.stat_refresh from ordinary enumeration because reading it flushes per-CPU statistics.
Persistence belongs to a particular loader
A runtime assignment does not create a persistent configuration file. Conversely, saving a drop-in does not apply it immediately. Identify which component applies settings at boot and on reload before reasoning about precedence.
For procps --system, same-named files in higher-priority directories mask lower-priority copies. The selected drop-ins are applied in filename order, regardless of directory; /etc/sysctl.conf is then read last. Systemd’s sysctl.d loader also combines directory priority with filename ordering, but does not directly read /etc/sysctl.conf. Distribution-provided links can still make that file participate through a drop-in. Inspect the installation rather than assuming the pathname alone settles the question.
This has two distinct override rules. A local file can replace a vendor file with the same basename, or a differently named file can override individual assignments by sorting later. Neither rule stops another service from writing the parameter after the loader finishes. Successful boot-time application and the value observed hours later are different facts.
Error policies are not interchangeable
Systemd’s sysctl.d documentation treats missing variables and permission failures as debug-level, nonfatal cases. Other assignment failures make its service fail after processing the remaining settings. A leading minus on an assignment suppresses failure for that assignment. These are systemd loader rules, not a promise about every invocation of procps sysctl.
Procps -e specifically ignores unknown-key errors; it does not mean every malformed value or denied write succeeds. Its configuration format also supports a leading minus to ignore an assignment’s error. Do not infer a portable exit status by combining options and error policies from different implementations.
When it breaks
A module-specific key may not exist when the boot loader runs. Check module availability and loader logs before concluding that a later read disproves the configuration syntax. Another writer may also overwrite a successfully applied value. Record the loader, file precedence, application time and subsequent effective value separately.
Containers add another boundary: mounts, permissions and namespaces affect visibility and write scope. Determine scope from the particular parameter’s documentation; a prefix such as net.* is not sufficient proof that a proposed change is isolated. Do not grant privileges or remount procfs merely to make a troubleshooting command work.
Check it quickly
This proposed read-only exercise requires Linux, Python 3, procps-ng 4.0.4 and readable procfs; its exact live invocation remains unrun. It compares one ordinary key through both interfaces, then checks a nonexistent key. It does not enumerate unknown handlers, load configuration, write settings or test boot persistence.
import os
import subprocess
from pathlib import Path
def require_result(result, status, stdout, stderr):
if (type(result.returncode) is not int or type(result.stdout) is not bytes
or type(result.stderr) is not bytes
or (result.returncode, result.stdout, result.stderr) != (status, stdout, stderr)):
raise RuntimeError(f"unexpected sysctl result: {result!r}")
def read_sysctl(*args):
return subprocess.run(
["sysctl", *args], capture_output=True, check=False, timeout=5,
env={**os.environ, "LC_ALL": "C"})
require_result(read_sysctl("--version"), 0,
b"sysctl from procps-ng 4.0.4\n", b"")
require_result(read_sysctl("kernel.ostype"), 0, b"kernel.ostype = Linux\n", b"")
require_result(read_sysctl("-n", "kernel.ostype"), 0, b"Linux\n", b"")
if Path("/proc/sys/kernel/ostype").read_bytes() != b"Linux\n":
raise RuntimeError("unexpected procfs kernel type")
require_result(read_sysctl("-n", "kernel.xbcatm_audit_missing_key"), 1, b"",
b"sysctl: cannot stat /proc/sys/kernel/xbcatm_audit_missing_key: "
b"No such file or directory\n")
print("matching kernel type: Linux")
print("exact missing-key diagnostic accepted")
Expect the matching-value and exact-diagnostic messages only after all checks succeed. The C-locale negative control requires status 1, empty stdout and the complete missing-path diagnostic, including its newline. Permission errors, missing tools, timeouts, partial output and unexpected success fail instead. Another procps version or diagnostic requires separate review, not a looser substring match. Pure response tests do not validate procfs or a live command. sysctl --system and sysctl -p apply settings; they are not configuration-preview commands and do not belong in this read-only check.
Sources
- procps sysctl(8), runtime interface, output options, unknown-key handling and system-file precedence, checked 2026-10-15.
- procps sysctl.conf(5), assignment syntax and loader distinction, checked 2026-10-15.
- systemd 252 sysctl.d documentation source, separators, missing modules and error policy, checked 2026-10-15.
- systemd 252 configuration precedence source, basename masking and lexicographic ordering, checked 2026-10-15.
- procps-ng 4.0.4 sysctl source, exact missing-path read error and failure status, checked 2026-10-19.