If you typically call utilities like uptime or ps to get system information from scripts, you may start using /proc from now on: your script can read /proc without invoking a new process, so it can be more efficient. One warning, though: /proc isn’t necessarily the same on every Linux system, and non-Linux systems may not have it at all. If you use /proc in a script that should be portable to other systems, check the other systems — or stick to the old standby utilities like uptime.

Introducing /proc

If you haven’t looked in /proc before, that’s a good place to start. See Listing One.

We won’t describe every part of /proc here; doing that would fill most of this article’s three pages! (And, to save space, we’ve omitted a lot of the entries from Listing One.) You can get details from the proc manual page. Let’s hit some highlights.

You can treat the virtual filesystem entries in /proc as if they’re on an actual hard disk: for instance, read the files with cat or less; list symbolic links (like /proc/self) with ls -l; cd into directories or run ls on them. The sidebar Reading /proc “files” efficiently explains an efficient way to get the contents of /proc “files.”

Reading /proc “files” efficiently

From a shell script, it’s more efficient to read a file with the bash operator $(<file), which opens a file directly without starting a new process. (Using a utility like cat starts a new process to run the program.) For instance, in a shell script that’s monitoring the system load average, you could read /proc/loadavg into the array named loadavg like this:

loadavg=( $(</proc/loadavg) )

Then ${loadavg[0]} has the first load average (the one-minute value), and so on.

Most of the names are self-explanatory. The numbered directories correspond to the processes running on your system; the number is the process PID. We’ll look at those, the the special symlink named self, in the next section.

cpuinfo gives detailed information on the machine’s processor(s).

loadavg gives the 1, 5, and 15-minute load average, the number of processes currently executing, and the last PID created.

partitions lists the current disk partitions, including major and minor device numbers and the number of blocks.

sys gives detailed system performance information in a series of subdirectories such as fs (filesystem), kernel, and net.

Per-process directories

As we said, the numbered directories have information about each process on the system. (Or you may see only your own processes — and many other named entries may have permissions that only allow superusers to read them.) These make a nice alternative to the Byzantine options and output formats of ps. For instance, if you’re trying to find the PPID of process 11037 (that is, the PID of the parent that started process 11037), look in /proc/11037/ppid:

$ cat /proc/11037/ppid
1043

Soon we’ll see more of what’s in these directories. By the way, one of those numeric directories in the ls -F output from Listing One is guaranteed not to exist anymore. Which one? It’s the directory that was created with information about that ls process itself. Once the ls process finished listing /proc, the ls process terminated, so its virtual directory in /proc vanished.

A process that needs to get information about itself can look in the numeric directory pointed to by the symbolic link /proc/self. This is worth a moment of thought before you use it. Consider this example:

(If you have ls aliased to run ls -F, you’ll get a result like /proc/self@ instead of the directory entries shown above. In that case, try /bin/ls /proc/self, or \ls /proc/self, to get a listing of the directory’s contents.)

Which process is that listing for: the shell that’s running ls, or for the ls process itself? Think: which process is actually reading /proc/self? Right: the ls process is reading /proc, so you’ll see information about ls in the listing.

To get information on your shell, use the $$ parameter. It expands into the current shell’s PID number. There’s an example in Listing Two for the shell whose PID happens to be 2588.

The contents of status are a handy alternative to reading many of the other files in the directory — which give the same information in smaller chunks.

Several of the entries are symbolic links. Reading the directory with ls -l shows each link’s target. For instance, the process’ current directory, pointed to by cwd, is /home/jpeek. (The shell’s current directory was /home/jpeek, which cat inherited when the shell started it.) The root entry points to the process’ root directory. That’s typically /, as you see here — but it can be different for a process run with chroot(2).

The fd subdirectory lists open file descriptors for the process… which leads us neatly into the next section.

The /proc/####/fd and /dev/std* subdirectories

I’ve talked before in this column about open files and file descriptor numbers. Two handy virtual parts of the Linux filesystem, the /proc/nnnn/fd and /dev/std* subdirectories, make it easy to explore these.

Let’s start with some special entries in /dev. The entries /dev/stdin, /dev/stdout, and /dev/stderr point to those open standard I/O files in the current process. These entries are actually symlinks pointing into the (virtual) /dev/fd subdirectory, as you can see by listing them:

(When you list that directory, you’re actually seeing the open files for the ls process — as explained earlier in this column. But, since ls inherits the open files from the process that started it — in this case, the open files from the shell that ran ls — what you see are the shell’s open files plus any other files that ls might have opened.

The standard input, output, and error all point to /dev/pts/5, which is our current terminal device — as tty confirms. So, another way to write to the standard error of your current process — instead of using the Bourne shells’ operator 1>&2 — is by writing to /dev/stderr. This is a great help to C-shell scripts, since they don’t have an easy way to write arbitrary text to the standard error (which is where error messages should be written):

echo an error > /dev/stderr

File descriptor 3 is also open in this process; it points to the fd subdirectory of process 26055. As we said, it’s for bash or ls.

This leads to a nice technique for exploring how open files are used in a shell: by listing /proc/self/fd after you change the shell’s open files.

Fiddling with file decriptors

When you experiment with file descriptors, it may be best to do from a shell script, or from an interactive subshell. That way, if you do something you didn’t mean to do (such as redirecting the standard output to a file, so you can’t see the outputs of commands), it’s easy to put things back to normal: simply terminate the subshell. Because changes to a child process don’t affect its parent process, the parent shell retains its original standard input and output after the subshell exits.

Let’s start a child bash shell. When we’re done playing — or, if something goes wrong — we can get back to a sane state by typing CTRL-D or exit to terminate the child shell. We’ll set the shell prompt to sub$ as a reminder that this is a subshell. To save typing, we’ll store a temporary filename in an environment variable with the arbitrary name T. (Environment variables are copied to child processes.) We’ll also make an alias that lists /proc/self/fd.

Listing Three shows some examples. (Try them yourself!) To avoid confusion here, we’ll omit listings for file descriptors that bash and ls may open.

The shell operator 1>&3 makes the standard output of echo (file descriptor 1) go to file descriptor 3 — which is the file in /tmp. We write three words there.

Reading the file with cat $T shows the words we wrote there.

As an example that’s somewhat opaque but also illustrative, cat /proc/self/fd/3 does the same thing! (Although the file /tmp/myfile is only open for writing from the shell, don’t let that confuse you. /proc/self/fd/3 is just a symbolic link pointing to the file that was opened by the shell. The command cat /proc/self/fd/3 is completely independent of the shell; cat is simply reading a file in the filesystem — which it finds via the symbolic link at /proc/self/fd/3.)

We run ls garbage to generate an error message on the standard output. Then we re-run the command with the operator 2>&3, which sends standard error (fd 2) to the file in /tmp via fd 3. Running cat shows the two lines in /tmp/myfile.

This illustrates another important reason to use open files and file descriptors instead of constantly re-opening a file from a script: the file stays open, and you can keep adding text to it, until you close the open file or end the shell process that’s holding the file open.

We end the shell subprocess with exit. That automatically closes the open file /tmp/myfile. Then we remove the file and the environment variable that held its name.

Experiment!

There’s a lot more to see in /proc, and a lot to learn from experimenting with /proc/self. Until next time, try exploring and see what you find.

In addition to what Jerry have wrote I want to clearify a few more files within a process proc directory:

exe is a link to the binary which started the process, but if the process is started for example(perl test.pl) you will see exe ponting perl and not test.pl

mounts is the list of the mount points as it was presenting during the start of the process, if you have mounted or unmounted a mountpoint during the execution of the process, it will not know about that since this is a copy of /proc/mounts and not a link

limits contains a list with the current ulimits set for the current process

environ is the environment that the process saw when it was started

cmdline is almost the same as exe but it usually has the arguments that have been added on the command line when the process was started.

The interesting thing about environ and cmdline is that the options there are not separated and you have to know for what you are searching

I was curious if you ever thought of changing the layout of your site? Its very well written; I love what youve got to say. But maybe you could a little more in the way of content so people could connect with it better. Youve got an awful lot of text for only having 1 or 2 images. Maybe you could space it out better?