I recently had a mock interview with a senior Linux administrator who asked whether I could collect CPU, memory, and disk-usage information from a Bash script without using top, free, df, or any external commands. My first answer was no, since I normally rely on standard utilities and monitoring tools when troubleshooting systems.
The interviewer then hinted at the /proc and /sys virtual filesystems. That made me realize that many familiar Linux commands are mainly presenting data already exposed by the kernel.
I understand the general idea, but I am less clear on the implementation details:
- How do you calculate CPU utilization from successive readings of /proc/stat?
- Which fields in /proc/meminfo should be used to determine memory usage, especially MemAvailable, buffers, cache, reclaimable memory, and shared memory?
- How can filesystem capacity and available space be calculated without df? Is statvfs the appropriate interface, and can it be accessed under the no-external-commands restriction?
- What Bash built-ins can be used to parse these files without spawning commands such as cat, grep, or awk?
I am interested in both practical examples and the reasoning behind the calculations. I would also like to know whether this is a useful interview question for a general Linux administrator, or whether it is mainly relevant to embedded systems, stripped-down environments, or situations where normal utilities are unavailable.
5 Answers
Filesystem usage is the awkward part. /proc and /sys do not generally provide the same per-filesystem block accounting that df displays. The usual underlying interface is the statvfs system call, which returns filesystem statistics for a path.
The key values are typically:
- total bytes = f_blocks * f_frsize
- free bytes = f_bfree * f_frsize
- non-root available bytes = f_bavail * f_frsize
- used bytes = (f_blocks - f_bfree) * f_frsize
The distinction between f_bfree and f_bavail matters because filesystems may reserve blocks for privileged use. A pure Bash script cannot directly invoke a system call unless an already available interpreter or utility exposes it, so a strict no-external-commands requirement makes disk usage much harder than CPU or memory. If the interviewer expects a Bash-only answer, it is worth clarifying whether shell built-ins are allowed but system calls through another language are not.
For CPU usage, read the first line beginning with cpu from /proc/stat twice, with a delay between readings. The values are cumulative jiffy counters: user, nice, system, idle, iowait, irq, softirq, steal, guest, and guest_nice.
For each sample, add all the counters to get total time. Add idle and iowait to get idle time. Then calculate the differences between samples:
CPU percentage = ((delta_total - delta_idle) / delta_total) * 100
Using deltas is essential because the values in /proc/stat continually increase. The guest counters are already included in user and nice on Linux, so implementations need to avoid accidentally counting them twice if they classify fields separately.
The units are jiffies, or scheduler ticks, rather than seconds. You generally do not need to convert them for the percentage calculation because both readings use the same unit.
The figures are useful for monitoring, but they are still snapshots exposed through /proc, not a perfect trace of every event. That is normally accurate enough for utilization estimates.
The parsing itself can be done without cat, grep, cut, or awk by redirecting a file into while read and using Bash built-ins such as read, case, arithmetic expansion, parameter expansion, printf, and test. That demonstrates knowledge of the shell restriction.
However, there is a difference between knowing how the kernel exposes the counters and writing production-quality monitoring code. A real implementation should consider counter wraparound, missing fields, container namespaces, mount types, units, permissions, and the fact that /proc values can vary between kernel versions.
For memory, /proc/meminfo reports values in kB. The simplest modern calculation is:
used = MemTotal - MemAvailable
MemAvailable is preferable to just subtracting MemFree because it estimates how much memory can be given to applications without heavy swapping. If MemAvailable is unavailable on an older kernel, an approximate fallback can be built from MemFree, Buffers, Cached, and SReclaimable, while accounting for Shmem. The exact formula has changed over time, so copying a current implementation from a trusted system utility is safer than assuming one universal formula.
In Bash, you can read the file directly with a while-read loop and match the field names using a case statement. Arithmetic expansion is sufficient for integer percentages, though it will truncate decimals.
A Bash-only approach can read MemTotal and MemAvailable directly, then calculate ((total - available) * 100 / total). It is a reasonable basic answer as long as the units and integer rounding are explained.
I think this is a reasonable question for roles involving low-level Linux, embedded devices, stripped-down container images, or recovery work where normal utilities may be missing. It is less useful as a memorization test for a general administrator. A stronger interview would allow documentation or provide a small environment and evaluate the candidate's approach: identify the kernel data source, take consistent samples, explain assumptions, and validate the result.
Most of the time, using top, free, df, sar, or a library is the practical choice. The important skill is understanding what those tools depend on and knowing how to investigate when the usual tools are unavailable.
That distinction matches my concern. I could research and write these scripts on the job, but recalling every field and formula under interview pressure is not the same as demonstrating sound troubleshooting skills.

Exactly. Reading /proc/mounts tells you what is mounted, but not the block usage for each mount. For a robust df replacement, statvfs is the correct conceptual interface, even if Bash alone cannot conveniently call it.