sysfs Explained: What /sys Is and How to Read It
If you have ever pasted a command that echoes a value into a path starting /sys, you have used sysfs without necessarily knowing what you were writing to. It is where the kernel exposes devices, drivers and their settings as files.
How it differs from /proc
Both are virtual filesystems that exist only in memory. The split is about subject matter.
/proc began as a view of running processes and then accumulated a great deal of other kernel information because there was nowhere else to put it. Our proc filesystem guide covers it.
/sys was added later with a deliberate design: one value per file, arranged according to the kernel’s internal device model.
mount | grep sysfs
# sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
The one-value rule is why reading sysfs from a script is pleasant and reading procfs often is not. cat gives you a number, not a table to parse.
The tuning knobs under /proc/sys are the confusing exception. Those are sysctl, which belongs to procfs despite the name, and our sysctl guide covers them.
The layout
ls /sys
# block bus class dev devices firmware fs kernel module power
/sys/devices is the real hierarchy, organised by how hardware is physically connected. Everything else is a view onto it.
/sys/class groups devices by what they do, regardless of how they attach. This is the one you want almost every time.
/sys/block is block devices specifically.
/sys/bus groups by bus: pci, usb, i2c, and so on.
/sys/module exposes loaded modules and their parameters.
ls /sys/class/
# net power_supply thermal hwmon backlight leds block tty drm ...
Nearly every practical path starts /sys/class/, because you usually want “the network interfaces” rather than “whatever is hanging off this PCI bridge”.
Reading useful things
Battery:
cat /sys/class/power_supply/BAT0/capacity
cat /sys/class/power_supply/BAT0/status
cat /sys/class/power_supply/BAT0/cycle_count
This is where upower and every desktop battery applet get their numbers. Handy for a status bar or script, and covered further in our power management guide.
Temperature:
# raw, in millidegrees
cat /sys/class/thermal/thermal_zone0/temp
cat /sys/class/thermal/thermal_zone0/type
# all of them
for z in /sys/class/thermal/thermal_zone*; do
printf '%s %s\n' "$(cat "$z"/type)" "$(cat "$z"/temp)"
done
Divide by 1000 for degrees Celsius. lm-sensors reads /sys/class/hwmon and labels it properly.
Network interfaces:
cat /sys/class/net/eth0/address # MAC
cat /sys/class/net/eth0/speed # negotiated, Mbps
cat /sys/class/net/eth0/operstate # up or down
cat /sys/class/net/eth0/mtu
Disks:
cat /sys/block/sda/queue/rotational # 1 spinning, 0 solid state
cat /sys/block/sda/queue/scheduler # active one in brackets
cat /sys/block/sda/size # in 512-byte sectors
rotational is worth knowing, because it is what tools consult to decide defaults, and virtual disks sometimes report it wrongly.
Writing to it
# change the I/O scheduler
echo mq-deadline | sudo tee /sys/block/sda/queue/scheduler
# screen brightness
echo 800 | sudo tee /sys/class/backlight/intel_backlight/brightness
# a keyboard LED
echo 1 | sudo tee /sys/class/leds/input3::capslock/brightness
Three things to expect.
tee rather than plain redirection. sudo echo x > /file runs the redirection as your user, not as root, so it fails. This is a shell behaviour rather than a sysfs one, covered in our redirection guide.
Some files are read only. No privilege changes that; the attribute simply has no write handler.
A write can be rejected. The driver validates the value, and the reason usually appears in dmesg rather than in the shell error.
sudo dmesg -w # watch while you attempt the write
Nothing persists
sysfs is rebuilt from scratch at boot. A value you write is gone after a restart.
To make it permanent, pick the mechanism that suits the thing:
# udev rule, for device attributes
# /etc/udev/rules.d/60-schedulers.rules
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", \
ATTR{queue/scheduler}="none"
# systemd-tmpfiles, for simple one-shot writes
# /etc/tmpfiles.d/backlight.conf
w /sys/class/backlight/intel_backlight/brightness - - - - 800
Kernel command line parameters handle the ones that must be set before userspace exists, as our kernel parameters guide covers. A small systemd service works for anything that needs ordering or logic, per our service file guide.
Our udev rules post covers the first option properly, and it is the right one for most device attributes.
Finding the path for a device
Guessing at paths is unnecessary.
# everything about a device and its parents
udevadm info -a -n /dev/sda | head -40
# just the device path
udevadm info -q path -n /dev/sda
# /devices/pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0/block/sda
# follow a class symlink back to the real hierarchy
readlink -f /sys/class/net/eth0
udevadm info -a is the important one. It walks up the parent chain printing every attribute at each level, which is both how you find the value you want and how you work out what to match on in a rule.
Module parameters
# what a loaded module was given
ls /sys/module/i915/parameters/
cat /sys/module/i915/parameters/enable_psr
# describe them without loading
modinfo -p i915
Some are writable at runtime, most are not. The ones that are not have to be set at load time, through /etc/modprobe.d/, which our kernel modules guide covers.
The dangerous corners
Most of sysfs is harmless to poke at, since nothing survives a reboot. A few attributes act immediately and irreversibly.
# removes a device from the running system, now
echo 1 > /sys/bus/pci/devices/0000:01:00.0/remove
# resets a device
echo 1 > /sys/bus/pci/devices/0000:01:00.0/reset
# forces a bus rescan, the usual way back from the above
echo 1 | sudo tee /sys/bus/pci/rescan
These are genuinely useful, for GPU passthrough and for hot-plugging hardware that did not appear on its own. They are also how you detach a controller holding a mounted filesystem, which ends exactly as badly as it sounds.
Read the attribute name before writing to it, and prefer cat first when you are exploring.
A worked example
Suppose a laptop fan is loud and you want to know what the machine thinks is hot.
# every thermal zone, labelled
for z in /sys/class/thermal/thermal_zone*; do
printf '%-22s %5.1f C\n' "$(cat "$z"/type)" "$(( $(cat "$z"/temp) / 1000 ))"
done
# the trip points that trigger cooling
cat /sys/class/thermal/thermal_zone0/trip_point_*_temp
cat /sys/class/thermal/thermal_zone0/trip_point_*_type
# is the CPU being throttled
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
That tells you which sensor is triggering, at what threshold, and whether the CPU is actually being held back, which is a better starting point than changing settings at random. Our CPU frequency guide covers what to do about it.
Frequently Asked Questions
What is the difference between /proc and /sys?
procfs began as a view of running processes and accumulated a great deal of unrelated kernel information along the way. sysfs was added later with a strict design: one value per file, organised by the kernel device model. If it concerns a device or driver it belongs in /sys, and process information stays in /proc.
Do changes written to /sys survive a reboot?
No. sysfs lives entirely in memory and is rebuilt at every boot. To make a change permanent, use a udev rule, a systemd tmpfiles entry, a kernel command line parameter, or a small service that applies it at startup.
Why does writing to a file in /sys fail with permission denied as root?
Some attributes are read only by design, so no amount of privilege helps. Others reject a value the driver considers invalid, and a few can only be written while the device is idle. Check dmesg immediately afterwards, because the driver usually explains the refusal there.
How do I find the sysfs path for a specific device?
Use udevadm info with the device node, which prints the full device path and every attribute in the parent chain. That output is also exactly what you need when writing a udev rule, since it shows which attributes are available at which level.
Can I read battery or temperature information from /sys?
Yes. Battery state lives under /sys/class/power_supply and thermal readings under /sys/class/thermal and /sys/class/hwmon. Tools like upower and sensors are presenting the same values in a friendlier form, which is useful to know when you want them in a script.
Is it safe to experiment with writing to sysfs files?
Mostly, since nothing persists and a reboot undoes everything. The exceptions matter though: device removal and reset attributes act immediately, and writing to the wrong one can drop a disk out from under a mounted filesystem. Read before you write, and know what the attribute controls.