Chapter 1. Introduction

What’s Special About Unix?

If we were writing about any other operating system, “power tools” might mean “nifty add-on utilities to extend the power of your operating system.” That sounds suspiciously like a definition of Unix: an operating system loaded with decades’ worth of nifty add-on utilities.

Unix is unique in that it wasn’t designed as a commercial operating system meant to run application programs, but as a hacker’s toolset, by and for programmers. In fact, an early release of the operating system went by the name PWB (Programmer’s Work Bench).

When Ken Thompson and Dennis Ritchie first wrote Unix at AT&T Bell Labs, it was for their own use and for their friends and coworkers. Utility programs were added by various people as they had problems to solve. Because Bell Labs wasn’t in the computer business, source code was given out to universities for a nominal fee. Brilliant researchers wrote their own software and added it to Unix in a spree of creative anarchy, which has been equaled only with Linux, in the introduction of the X Window System (Section 1.22), and especially the blend of Mac and Unix with Darwin included in the Mac OS X.

Unlike most other operating systems, where free software remains an unsupported add-on, Unix has taken as its own the work of thousands of independent programmers. During the commercialization of Unix within the past several years, this incorporation of outside software has slowed down for larger Unix installations, such as Sun’s Solaris and HP’s hp-ux, but not stopped entirely. This is especially true with the newer lighter versions of Unix, such as the various flavors of Linux and Darwin.

Therefore, a book on Unix inevitably has to focus not just on add-on utilities (though we do include many of those), but on how to use clever features of the many utilities that have been made part of Unix over the years.

Unix is also important to power users because it’s one of the last popular operating systems that doesn’t force you to work behind an interface of menus, windows, and mouse with a “one-size(-doesn’t)-fit-all” programming interface. Yes, you can use Unix interfaces with windows and menus — and they can be great time savers in a lot of cases. But Unix also gives you building blocks that, with some training and practice, will give you many more choices than any software designer can cram onto a set of menus. If you learn to use Unix and its utilities from the command line, you don’t have to be a programmer to do very powerful things with a few keystrokes.

So, it’s also essential that this book teach you some of the underlying principles that make Unix such a tinkerer’s paradise.

In the body of this book, we assume that you are already moderately familiar with Unix — a journeyman hacker wanting to become a master. But at the same time, we don’t want to leave beginners entirely at sea; so in this chapter, we include some fundamental concepts. We’ve tried to intersperse some simple tips and tricks to keep things interesting, but the ratio of concept articles to tips is much higher than in any other part of the book. The concepts covered are also much more basic. If you aren’t a beginner, you can safely skip this chapter, though we may bounce you back here if you don’t understand something later in the book.

Don’t expect a complete introduction to Unix — if you need that, buy an introductory book. What you’ll find here is a selection of key concepts that you’ll need to understand to progress beyond the beginner stage, as well as answers to frequently asked questions and problems. In some ways, consider this introduction a teaser. If you are a beginner, we want to show you enough of Unix to whet your appetite for more.

Also, don’t expect everything to be in order. Because we don’t want you to get in the habit of reading through each chapter from beginning to end, as in most books, the articles in this chapter are in loose order. We’ve tried not to make you jump around too much, but we’ve also avoided a lot of the transitional material that makes reading most books a chore.

—TOR, JP, and SP

Power Grows on You

It has been said that Unix is not an operating system as much as it is a way of thinking. In The UNIX Programming Environment, Kernighan and Pike write that at the heart of the Unix philosophy “is the idea that the power of a system comes more from the relationships among programs than from the programs themselves.”

Most of the nongraphical utility programs that have run under Unix since the beginning, some 30 years ago, share the same user interface. It’s a minimal interface, to be sure — but one that allows programs to be strung together in pipelines to do jobs that no single program could do alone.

Most operating systems — including modern Unix and Linux systems — have graphical interfaces that are powerful and a pleasure to use. But none of them are so powerful or exciting to use as classic Unix pipes and filters, and the programming power of the shell.

A new user starts by stringing together simple pipelines and, when they get long enough, saving them for later execution in a file (Section 1.8), alias (Section 29.2), or function (Section 29.11). Gradually, if the user has the right temperament, he gets the idea that the computer can do more of the boring part of many jobs. Perhaps he starts out with a for loop (Section 28.9) to apply the same editing script to a series of files. Conditions and cases soon follow and before long, he finds himself programming.

On most systems, you need to learn consciously how to program. You must take up the study of one or more programming languages and expend a fair amount of concentrated effort before you can do anything productive. Unix, on the other hand, teaches programming imperceptibly — it is a slow but steady extension of the work you do simply by interacting with the computer.

Before long, you can step outside the bounds of the tools that have already been provided by the designers of the system and solve problems that don’t quite fit the mold. This is sometimes called hacking; in other contexts, it is called “engineering.” In essence, it is the ability to build a tool when the right one is not already on hand.

No single program, however well thought out, will solve every problem. There is always a special case, a special need, a situation that runs counter to the expected. But Unix is not a single program. It is a collection of hundreds of them, and with these basic tools, a clever or dedicated person can meet just about any computing problem.

Like the fruits of any advanced system, these capabilities don’t fall unbidden into the hands of new users. But they are there for the reaching. And over time, even those users who want a system they don’t have to think about will gradually reach out for these capabilities. Faced with a choice between an hour spent on a boring, repetitive task and an hour putting together a tool that will do the task in a flash, most of us will choose the latter.

— TOR

The Core of Unix

In recent times, more attention has been paid on the newer and more lightweight varieties of Unix: FreeBSD, Linux, and now Darwin — the version of BSD Unix that Apple used as the platform for the new Mac OS X. If you’ve worked with the larger Unix versions, you might be curious to see how it differs within these new environments.

For the most part, basic Unix functionality differs very little between implementations. For instance, I’ve not worked with a Unix box that doesn’t have vi (Section 21.7) installed. Additionally, I’ve also not found any Unix system that doesn’t have basic functionality, such as traversing directories with cd (Section 1.16) or getting additional help with man (Section 2.1).

However, what can differ between flavors of Unix is the behavior of some of the utilities and built-in commands, as well as the options. Even within a specific Unix flavor, such as FreeBSD, installations can differ because one installation uses the built-in version of a utility such as make (Section 40.3) and another installation has a GNU version of the same application.

An attempt was made to create some form of standardization with the POSIX effort. POSIX, which stands for Portable Operating System Interface, is an IEEE standard to work towards application interoperability. With this, C programs written on one flavor of Unix should work, with minimum modification, on another flavor of Unix.

Unfortunately, though the POSIX effort has had some impact on interoperability, there still are significant differences between Unix versions. In particular, something such as System V Unix can differ considerably from something such as Darwin.

However, there is stability in this seeming chaos: for the most part, the basic Unix utilities and commands behave the same in all Unix flavors, and aside from some optional differences, how a command works within one environment is exactly the same as in another environment. And if there are differences, using the facilities described in Chapter 2 should help you resolve these quickly.

— SP

Communication with Unix

Probably the single most important concept for would-be power users to grasp is that you don’t “talk” directly to the Unix operating system. Instead, you talk to a program — and that program either talks to Unix itself or it talks to another program that talks to Unix. (When we say “talk” here, we mean communication using a keyboard and a mouse.)

There are three general kinds of programs you’ll probably “talk” to:

  • The program called the shell (Section 27.1). A shell is a command interpreter. Its main job is to interpret the commands you type and to run the programs you specify in your command lines. By default, the shell reads commands from your tty and arranges for other programs to write their results there. The shell protects Unix from the user (and the user from Unix). It’s the main focus of this book (and the rest of this article).

  • An interactive command, running “inside” a tty, that reads what you type directly. These take input directly from the user, without intervention from the shell. The shell’s only job is to start them up. A text editor, a mail program, or almost any application program (such as word processing) includes its own command interpreter with its own rules. This book covers a few interactive commands — such as the vi editor — but its main focus is the shell and “noninteractive” utilities that the shell coordinates to do what needs doing.

  • A Graphical User Interface (GUI) with a desktop, windows, and so on. On Unix, a GUI is implemented with a set of running programs (all of which talk to Unix for you).

    Unix was around long before GUIs were common, and there’s no need to use a GUI to use Unix. In fact, Unix started in the days of teletypes, those clattering printing devices used to send telegrams. Unix terminals are still referred to as teletypes or ttys (Section 2.7).

The core of the Unix operating system is referred to as the kernel (Section 1.10). Usually, only programs talk to the kernel (through system calls). Users talk to one of the three previous types of programs, which interprets their commands and either executes them directly or passes them on to other programs. These programs may, in turn, request lower-level services from the kernel.

Let’s look at a specific example of using the shell. When you type a command to display files whose four-character filenames start with the letter “m”:

??? Section 1.13

% cat m???

it is the shell that finds the filenames, makes a complete list of them, and calls the cat (Section 12.2) command to print the expanded list. The cat command calls on the kernel to find each file on the disk and print its contents as a stream of characters on the display.

Why is this important? First of all, you can choose between several different shells (Section 1.6), each of which may have different rules for interpreting command lines.

Second, the shell has to interpret the command line you type and package it up for the command you are calling. Because the shell reads the command line first, it’s important to understand just how the shell changes what it reads.

For example, one basic rule is that the shell uses “whitespace” (spaces or tabs) to separate each “argument” of a command. But sometimes, you want the shell to interpret its arguments differently. For example, if you are calling grep (Section 13.1), a program for searching through files for a matching line of text, you might want to supply an entire phrase as a single argument. The shell lets you do this by quoting (Section 27.12) arguments. For example:

% grep "Power Tools" articles/*

Understanding how the shell interprets the command line, and when to keep it from doing so, can be very important in a lot of special cases, especially when dealing with wildcards (Section 1.13), like the * (asterisk) in the previous example.

You can think of the relationship of the kernel, the shell, and various Unix utilities and applications as looking like Figure 1-1.

Relationship of kernel, shell, utilities, and applications

Figure 1-1. Relationship of kernel, shell, utilities, and applications

Figure 1-1 shows that a user can interact with the shell, as well as directly with interactive commands like cat and ls. The shell transfers control to the commands it starts for you — then those commands may write the output you see. The shell also has some built-in commands (Section 1.9) that run directly within the shell itself. All of the commands shown in Figure 1-1 interact directly with Unix itself.

—TOR and JP

Programs Are Designed to Work Together

As pointed out by Kernighan and Pike in The UNIX Programming Environment, there are a number of principles that distinguish the Unix environment. One key concept is that programs are tools. Like all good tools, they should be specific in function, but usable for many different purposes.

In order for programs to become general-purpose tools, they must be data independent. This means three things:

  1. Within limits, the output of any program should be usable as the input to another.

  2. All of the information needed by a program should be either contained in the data stream passed to it or specified on the command line. A program should not prompt for input or do unnecessary formatting of output. In most cases, this means that Unix programs work with plain text files that don’t contain “nonprintable” or “control” characters.

  3. If no arguments are given, a program should read the standard input (usually the terminal keyboard) and write the standard output (usually the terminal screen).

Programs that can be used in this way are often called filters.

One of the most important consequences of these guidelines is that programs can be strung together in “pipelines” in which the output of one program is used as the input of another. A vertical bar (|) represents pipe and means “take the output of the program on the left and feed it into the program on the right.”

For example, you can pipe the output of a search program to another program that sorts the output, and then pipe the result to the printer program or redirect it to a file (Section 43.1).

Not all Unix programs work together in this way. An interactive program like the Emacs editor (Section 19.1) generally doesn’t read from or write to pipes you’d create on the command line. Instead, once the shell has started Emacs, the editor works independently of the shell (Section 1.4), reading its input and output directly from the terminal. And there are even exceptions to this exception. A program like less (Section 12.3) can read its standard input from a pipe and still interact with you at the keyboard. It does that by reading directly from your tty (Section 2.7).

— TOR

There Are Many Shells

With most operating systems, the command intepreter is built in; it is an integral part of the operating system. With Unix, your command interpreter is just another program. Traditionally, a command interpreter is called a “shell,” perhaps because it protects you from the underlying kernel — or because it protects the kernel from you!

In the early 1980s, the most common shells were the Bourne shell (sh) and the C shell (csh). The Bourne shell (Section 3.3) (named after its creator, Steve Bourne) came first. It was excellent for shell programming (Section 1.8). But many Unix users (who were also writing programs in the C language) wanted a more familiar programming syntax — as well as more features for interactive use. So the C shell came from Berkeley as part of their Unix implementation. Soon (on systems that gave you the choice, at least) csh was much more popular for interactive use than sh. The C shell had a lot of nice features that weren’t available in the original Bourne shell, including job control (Section 23.1) and history (Section 30.2). However, it wasn’t hard for a shell programmer or an advanced user to push the C shell to its limits.

The Korn shell (also named after its creator, David Korn) arrived in the mid-1980s. The ksh is compatible with the Bourne shell, but has most of the C shell’s features plus features like history editing (Section 30.14), often called command-line editing. The Korn shell was available only with a proprietary version of Unix, System V — but now a public-domain version named pdksh is widely available.

These days, most original C shell users have probably switched to tcsh (pronounced “T-shell”). It has all the features of csh and more — as well as fewer mis-features and outright bugs.

The “Bourne-again” shell, bash, is from the Free Software Foundation. It’s fairly similar to the Korn shell. It has most of the C shell’s features, plus command-line editing and a built-in help command. The programming syntax, though, is much more like the original Bourne shell — and many systems (including Linux) use bash in place of the original Bourne shell (but still call it sh).

The Z shell, zsh, is an interesting hybrid. It tries to be compatible with most features of all the other shells, with compatibility modes and a slew of options that turn off conflicting features. In its soul, though, zsh has a different way of doing some things. It’s been accused of feature creep. But zsh users love its flexibility.

There are other shells. If you’re a fan of the Bell Labs research operating system named Plan 9 (actually, Plan 9 from Outer Space), you’ll be happy to know that its shell, rc, has been ported to Unix. If you program in Tcl, you’ll probably be familiar with tclsh , which lets you intermix Unix commands with Tcl commands. (And we can’t forget wish , the shell that’s a superset of tclsh: it uses Tcl/Tk commands to let you build graphical interfaces as you go.) Least — but certainly not last — if you’re a minimalist who needs the original sh, a newer shell named ash emulates the late-1980s Bourne shell.

In this book, we try to be as generic as we can. Where we need to get specific, many examples are shown in the style of both the Bourne shell and the C shell — for instance, we’ll often show Bourne-shell functions side-by-side with C-shell aliases. Because bash and ksh can read scripts written for the original Bourne shell, we use original sh syntax to make our shell programming as portable as possible.

Where we talk about “the Bourne shell” or sh, it’s usually a safe bet that the information applies to bash and ksh too. In the same way, “the C shell” generally also means tcsh.

—JP and ML

Which Shell Am I Running?

You can usually tell which family your shell belongs to by a character in the prompt it displays. Bourne-type shells, such as bash , usually have $ in the prompt. The C shell uses % (but tcsh users often use >).

If your shell has superuser (Section 1.18) privileges, though, the prompt typically ends with a hash, #.

To check the shell that runs automatically when you log in to Unix, type one of these commands (the second is for systems that use NIS, Sun’s Network Information Service, to manage network-wide files):

% grep
               yourloginname /etc/passwd
% ypmatch 
               yourloginname passwd

You should get back the contents of your entry in the system password file. For example:

shelleyp:*:1006:1006:Shelley Powers:/usr/home/shelleyp:/usr/local/bin/bash

The fields are separated by colons, and the default shell is usually specified in the last field.

Note that in Mac OS X, passwords are managed and stored in Netinfo by default. To store the passwords in /etc/passwd, you’ll need to configure this using Netinfo.

—TOR and SP

Anyone Can Program the Shell

One of the really wonderful things about the shell is that it doesn’t just read and execute the commands you type at a prompt. The shell is a complete programming language.

The ease of shell programming is one of the real highlights of Unix for novices. A shell program need be no more than a single complex command line saved in a file — or a series of commands.

For example, let’s say that you occasionally need to convert a Macintosh Microsoft Word file for use on your Unix system. Word lets you save the file in ASCII format. But there’s a catch: the Mac uses a carriage return ASCII character 015 to mark the end of each line, while Unix uses a linefeed (ASCII 012). As a result, with Unix, the file looks like one long paragraph, with no end in sight.

That’s easy to fix: the Unix tr (Section 21.11) command can convert every occurrence of one character in a file to another:

bash-2.04$ tr '\015' '\012' < 
               file.mac
                > 
               file.unix

But you’re a novice, and you don’t want to remember this particular piece of magic. Fine. Save the first part of this command line in a file called mac2unix in your personal bin directory (Section 7.4):

tr '\015' '\012'

Make the file executable with chmod (Section 50.5):

bash-2.04$ chmod +x mac2unix

Now you can say:

bash-2.04$ mac2unix < 
               file.mac
                > 
               file.unix

But why settle for that? What if you want to convert a bunch of files at once? Easy. The shell includes a general way of referring to arguments passed to a script and a number of looping constructs. The script:

for Section 35.21, $x Section 35.9

for x
do
    echo "Converting $x"
    tr '\015' '\012' < "$x" > "tmp.$x"
    mv "tmp.$x" "$x"
done

will convert any number of files with one command, replacing each original with the converted version:

bash-2.04$ mac2unix 
               file1 file2 file3 ...

As you become more familiar with Unix, it quickly becomes apparent that doing just a little homework can save hours of tedium. This script incorporates only two simple programming constructs: the for loop and variable substitution (Section 35.9, Section 35.3).[1] As a new user with no programming experience, I learned these two constructs by example: I saved a skeleton for loop in a file and simply filled in the blanks with whatever commands I wanted to repeat. Section 35.2 has more about shell programming.

In short, Unix is sometimes difficult because it is so rich and complex. The user who doesn’t want to learn the complexity doesn’t have to — the basic housekeeping commands are simple and straightforward. But the user who wants to take the time to investigate the possibilities can uncover a wealth of useful tools.

— TOR

Internal and External Commands

Some commands that you type are internal, which means they are built into the shell, and it’s the shell that performs the action. For example, the cd command is built-in. The ls command, on the other hand, is an external program stored in the file /bin/ls.

The shell doesn’t start a separate process to run internal commands. External commands require the shell to fork and exec (Section 27.2) a new subprocess (Section 24.3); this takes some time, especially on a busy system.

When you type the name of a command, the shell first checks to see if it is a built-in command and, if so, executes it. If the command name is an absolute pathname ( Section 1.16) beginning with /, like /bin/ls, there is no problem: the command is likewise executed. If the command is neither built-in nor specified with an absolute pathname, most shells (except the original Bourne shell) will check for aliases (Section 29.2) or shell functions (Section 29.11), which may have been defined by the user — often in a shell setup file (Section 3.3) that was read when the shell started. Most shells also “remember” the location of external commands (Section 27.6); this saves a long hunt down the search path. Finally, all shells look in the search path for an executable program or script with the given name.

The search path is exactly what its name implies: a list of directories that the shell should look through for a command whose name matches what is typed.

The search path isn’t built into the shell; it’s something you specify in your shell setup files.

By tradition, Unix system programs are kept in directories called /bin and /usr/bin, with additional programs usually used only by system administrators in either /etc and /usr/etc or /sbin and /usr/sbin. Many versions of Unix also have programs stored in /usr/ucb (named after the University of California at Berkeley, where many Unix programs were written). There may be other directories containing programs. For example, the programs that make up the X Window System (Section 1.22) are stored in /usr/bin/X11. Users or sites often also have their own directories where custom commands and scripts are kept, such as /usr/local/bin or /opt.

The search path is stored in an environment variable (Section 35.3) called PATH (Section 35.6). A typical PATH setting might look something like this:

PATH=/bin:/usr/bin:/usr/bin/X11:/usr/ucb:/home/tim/bin:

The path is searched in order, so if there are two commands with the same name, the one that is found first in the path will be executed. For example, your system certainly has the ls command we mentioned earlier — and it’s probably in /bin/ls.

You can add new directories to your search path on the fly, but the path is usually set in shell setup files.

— TOR

The Kernel and Daemons

If you have arrived at Unix via Windows 2000 or some other personal computer operating system, you will notice some big differences. Unix was, is, and always will be a multiuser operating system. It is a multiuser operating system even when you’re the only person using it; it is a multiuser operating system even when it is running on a PC with a single keyboard; and this fact has important ramifications for everything that you do.

Why does this make a difference? Well, for one thing, you’re never the only one using the system, even when you think you are. Don’t bother to look under your desk to see if there’s an extra terminal hidden down there. There isn’t. But Unix is always doing things “behind your back,” running programs of its own, whether you are aware of it or not. The most important of these programs, the kernel, is the heart of the Unix operating system itself. The kernel assigns memory to each of the programs that are running, partitions time fairly so that each program can get its job done, handles all I/O (input/output) operations, and so on. Another important group of programs, called daemons, are the system’s “helpers.” They run continuously — or from time to time — performing small but important tasks like handling mail, running network communications, feeding data to your printer, keeping track of the time, and so on.

Not only are you sharing the computer with the kernel and some mysterious daemons, you’re also sharing it with yourself. You can issue the ps x (Section 24.5) command to get a list of all processes running on your system. For example:

  PID TTY    STAT  TIME COMMAND
18034 tty2   S     0:00 -zsh
18059 ?      S     0:01 ssh-agent
18088 tty2   S     0:00 sh /usr/X11R6/bin/startx
18096 tty2   S     0:00 xinit /etc/X11/xinit/xinitrc -- :0 -auth /home/jpeek/
18101 tty2   S     0:00 /usr/bin/gnome-session
18123 tty2   S     0:33 enlightenment -clientId default2
18127 tty2   S     0:01 magicdev --sm-client-id=default12
18141 tty2   S     0:03 panel --sm-client-id default8
18145 tty2   S     0:01 gmc --sm-client-id default10
18166 ?      S     1:20 gnomepager_applet --activate-goad-server gnomepager_a
18172 tty2   S     0:01 gnome-terminal
18174 tty2   S     0:00 gnome-pty-helper
18175 pts/0  S     0:00 zsh
18202 tty2   S     0:49 gnome-terminal
18203 tty2   S     0:00 gnome-pty-helper
18204 pts/1  S     0:01 zsh
18427 pts/1  T     0:00 man zshjp
18428 pts/1  T     0:00 sh -c /bin/gunzip -c /home/jpeek/.man/cat1/zshjp.1.gz
18430 pts/1  T     0:03 /usr/bin/less -is
18914 pts/1  T     0:02 vi upt3_changes.html
 1263 pts/1  T     0:00 vi urls.html
 1511 pts/1  T     0:00 less coding
 3363 pts/1  S     0:00 vi 1007.sgm
 4844 tty2   S     0:24 /usr/lib/netscape/netscape-communicator -irix-session
 4860 tty2   S     0:00 (dns helper)
 5055 pts/1  R     0:00 ps x

This output tells us that the user has only three windows open. You may think that they’re only running four or five programs, but the computer is actually doing a lot more. (And, to keep this brief, we aren’t showing all the lines of output!) The user logged into his Linux system on virtual console (Section 23.12) 2, which shows as tty2 in the TTY column; a lot of programs are running there, including the X Window System (Section 1.22) (which actually runs itself as another user — root — so its process isn’t listed here). The user is also running Gnome and Enlightenment, which keep track of the workstation’s display. Two of the windows are Gnome terminals, which are windows that act like separate terminals; each has its own tty, pts/0 and pts/1. And the list continues.

If you are running a different window system (or no window system at all) or different utility programs, you will see something different. But we guarantee that you’re running at least two programs, and quite likely many more. If you want to see everything that’s running, including the daemons, type the command ps aux (Berkeley-style ps) or ps -el (for many other flavors of ps). You’ll be impressed.

Because there is so much going on at once, Unix requires a different way of thinking. The Unix kernel is a traffic cop that mediates different demands for time, memory, disks, and so on. Not only does the kernel need to run your programs, but it also needs to run the daemons, any programs that other users might want to start, or any programs that you may have scheduled to run automatically, as discussed in Chapter 23. When it runs a program, the kernel allocates a small slice of time — up to a second — and lets the program run until that slice is used up or until the program decides to take a rest of its own accord (this is called "sleeping”). At this point, regardless of whether the program is finished, the kernel finds some other program to run. The Unix kernel never takes a vacation: it is always watching over the system.

Once you understand that the kernel is a manager that schedules many different kinds of activity, you understand a lot about how Unix works. For example, if you have used any computer system previously, you know that it’s a bad idea to turn the computer off while it is writing something to disk. You will probably destroy the disk, and you could conceivably damage the disk drive. The same is true for Unix — but with an important complication. Any of the programs that are running can start doing something to the disk at any time. One of the daemons makes a point of accessing the disk drive every 30 seconds or so, just to stay in touch. Therefore, you can’t just turn a Unix computer off. You might do all sorts of damage to the system’s files — and not just your own, but conceivably files belonging to many other users. To turn a Unix system off, you must first run a program called shutdown, which kicks everyone off the system, makes sure that a daemon won’t try to play with a disk drive when you aren’t looking, and runs a program named sync to make sure that the disks have the latest version of everything. Only then is it safe to pull the switch. When you start up a Unix system, it automatically runs a program called fsck , which stands for “filesystem check”; its job is to find out if you shut down the system correctly and try to fix any damage that might have happened if you didn’t.

—ML and JP

Filenames

Like all operating systems, Unix files have names. (Unix directories, devices, and so on also have filenames — and are treated like files (Section 1.19).) The names are words (sequences of characters) that let you identify a file. Older versions of Unix had some restrictions on the length of a filename (14 characters), but modern versions have removed these restrictions for all practical purposes. Sooner or later you will run into a limit, but if so, you are probably being unnecessarily verbose.

Technically, a filename can be made from almost any group of characters (including nonprinting characters and numbers) except a slash (/). However, you should avoid filenames containing most punctuation marks and all nonprinting characters. To be safe, limit your filenames to the following characters:

Upper- and lowercase characters

Unix filenames are always case sensitive. That is, upper- and lowercase letters are always different (unlike Microsoft Windows and others that consider upper- and lowercase letters the same). Therefore, myfile and Myfile are different files. It is usually a bad idea to have files whose names differ only in their capitalization, but that’s your decision.

Underscores (_)

Underscores are handy for separating “words” in a filename to make them more readable. For example, my_long_filename is easier to read than mylongfilename.

Periods (.)

Periods are used by some programs (such as the C compiler) to separate filenames from filename extensions (Section 1.12). Extensions are used by these programs to recognize the type of file to be processed, but they are not treated specially by the shell, the kernel, or other Unix programs.

Filenames that begin with a period are treated specially by the shell: wildcards won’t match (Section 1.13) them unless you include the period (like .*). The ls command, which lists your files, ignores files whose names begin with a period unless you give it a special option (ls -a (Section 8.9)). Special configuration files are often “hidden” in directories by beginning their names with a period.

Certain other punctuation

About the only other punctuation mark that is always safe is the comma (,), although it isn’t part of the POSIX-portable character set.

I’m so dead-set against using weird, nonprinting characters in filenames that I won’t even tell you how to do it. I will give you some special techniques for deleting files with weird names (Section 14.11), though, in case you create some by accident.

Some things to be aware of:

  • Unix does not have any concept of a file version. There are some revision control programs (Section 39.4) that implement their own notion of a version, but there is nothing built into the operating system that handles this for you. If you are editing a file, don’t count on Unix to save your previous versions — you can program this (Section 35.16, Section 18.14) though, if you want to; the GNU Emacs editor also makes backups (Section 19.4).

  • Once you delete a file in Unix, it is gone forever (Section 14.3). You can’t get it back without restoring it from a backup. So be careful when you delete files. Later, we’ll show you programs that will give you a “grace period” between the time you delete a file and the time it actually disappears.

— ML

Filename Extensions

In Microsoft Windows and some other operating systems, filenames often have the form name.extension. For example, plain text files have extensions such as .txt. The operating system treats the extension as separate from the filename and has rules about how long it must be, and so forth.

Unix doesn’t have any special rules about extensions. The dot has no special meaning as a separator, and extensions can be any length. However, a number of programs (especially compilers) make use of extensions to recognize the different types of files they work with. In addition, there are a number of conventions that users have adopted to make clear the contents of their files. For example, you might name a text file containing some design notes notes.txt.

Table 1-1 lists some of the filename extensions you might see and a brief description of the programs that recognize them.

Table 1-1. Filename extensions that programs expect

Extension

Description

.a

Archive file (library)

.c

C program source file

.f

FORTRAN program source file

.F

FORTRAN program source file to preprocess

.gz

gzip ped file (Section 15.6)

.h

C program header file

.html or .htm

HTML file for web servers

.xhtml

XHTML file for web servers

.o

Object file (compiled and assembled code)

.s

Assembly language code

.z

Packed file

.Z

Compressed file Section 15.6)

.1 to .8

Online manual (Section 2.1) source file

~

Emacs editor backup file (Section 19.4)

In Table 1-2 are some extensions often used by users to signal the contents of a file, but are not actually recognized by the programs themselves.

Table 1-2. Filename extensions for user’s benefit

Extension

Description

.tar

tar archive (Section 39.2)

.tar.gz or .tgz

gzip ped (Section 15.6) tar archive (Section 39.2)

.shar

Shell archive

.sh

Bourne shell script (Section 1.8)

.csh

C shell script

.mm

Text file containing troff’s mm macros

.ms

Text file containing troff’s ms macros

.ps

PostScript source file

.pdf

Adobe Portable Document Format

—ML and TOR

Wildcards

The shells provide a number of wildcards that you can use to abbreviate filenames or refer to groups of files. For example, let’s say you want to delete all filenames ending in .txt in the current directory (Section 1.16). You could delete these files one by one, but that would be boring if there were only 5 and very boring if there were 100. Instead, you can use a wildcarded name to say, “I want all files whose names end with .txt, regardless of what the first part is.” The wildcard is the “regardless” part. Like a wildcard in a poker game, a wildcard in a filename can have any value.

The wildcard you see most often is * (an asterisk), but we’ll start with something simpler: ? (a question mark). When it appears in a filename, the ? matches any single character. For example, letter? refers to any filename that begins with letter and has exactly one character after that. This would include letterA, letter1, as well as filenames with a nonprinting character as their last letter, such as letter^C.

The * wildcard matches any character or group of zero or more characters. For example, *.txt matches all files whose names end with .txt; c* matches all files whose names start with c; c*b* matches names starting with c and containing at least one b; and so on.

The * and ? wildcards are sufficient for 90 percent of the situations that you will find. However, there are some situations that they can’t handle. For example, you may want to list files whose names end with .txt, mail, or let. There’s no way to do this with a single *; it won’t let you exclude the files you don’t want. In this situation, use a separate * with each filename ending:

*.txt *mail *let

Sometimes you need to match a particular group of characters. For example, you may want to list all filenames that begin with digits or all filenames that begin with uppercase letters. Let’s assume that you want to work with the files program.n, where n is a single-digit number. Use the filename:

program.[0123456789]

In other words, the wildcard [ character-list ] matches any single character that appears in the list. The character list can be any group of ASCII characters; however, if they are consecutive (e.g., A-Z, a-z, 0-9, or 3-5, for that matter), you can use a hyphen as shorthand for the range. For example, [a-zA-Z] means any alphabetic English character.

There is one exception to these wildcarding rules. Wildcards never match /, which is both the name of the filesystem root (Section 1.14) and the character used to separate directory names in a path (Section 1.16). The only way to match on this character is to escape it using the backslash character ( \). However, you’ll find it difficult to use the forward slash within a filename anyway (the system will keep trying to use it as a directory command).

If you are new to computers, you probably will catch on to Unix wildcarding quickly. If you have used any other computer system, you have to watch out for one important detail. Virtually all computer systems except for Unix consider a period (.) a special character within a filename. Many operating systems even require a filename to have a period in it. With these operating systems, a * does not match a period; you have to say *.*. Therefore, the equivalent of rm * does virtually nothing on some operating systems. Under Unix, it is dangerous: it means “delete all the files in the current directory, regardless of their name.” You only want to give this command when you really mean it.

But here’s the exception to the exception. The shells and the ls command consider a . special if it is the first character of a filename. This is often used to hide initialization files and other files with which you aren’t normally concerned; the ls command doesn’t show these files unless you ask (Section 8.9) for them. If a file’s name begins with ., you always have to type the . explicitly. For example, .*rc matches all files whose names begin with . and end with rc. This is a common convention for the names of Unix initialization files.

Table 1-3 has a summary of common wildcards.

Table 1-3. Common shell wildcards

Wildcard

Matches

?

Any single character

*

Any group of zero or more characters

[ab]

Either a or b

[a-z]

Any character between a and z, inclusive

Wildcards can be used at any point or points within a path. Remember, wildcards only match names that already exist. You can’t use them to create new files (Section 28.3) — though many shells have curly braces ({}) for doing that. Section 33.3 explains how wildcards are handled, and Section 33.2 has more about wildcards, including specialized wildcards in each of the shells.

— ML

The Tree Structure of the Filesystem

A multiuser system needs a way to let different users have different files with the same name. It also needs a way to keep files in logical groups. With thousands of system files and hundreds of files per user, it would be disastrous to have all of the files in one big heap. Even single-user operating systems have found it necessary to go beyond “flat” filesystem structures.

Almost every operating system solved this problem by implementing a tree-structured, or hierarchical, filesystem. Unix is no exception. A hierarchical filesystem is not much different from a set of filing cabinets at the office. Your set of cabinets consists of many individual cabinets. Each individual cabinet has several drawers; each drawer may have several partitions in it; each partition may have several hanging (Pendaflex) folders; and each hanging folder may have several files. You can specify an individual file by naming the filing cabinet, the drawer, the partition, the group of folders, and the individual folder. For example, you might say to someone: “Get me the `meeting of July 9’ file from the Kaiser folder in the Medical Insurance Plans partition in the Benefits drawer of the Personnel file cabinet.” This is backwards from the way you’d specify a filename, because it starts with the most specific part, but the idea is essentially the same.

You could give a complete path like this to any file in any of your cabinets, as shown in Figure 1-2. The concept of a “path” lets you distinguish your July 9 meeting with Kaiser from your July 9 interview with a job applicant or your July 9 policy-planning meeting. It also lets you keep related topics together: it’s easy to browse through the “Medical Insurance” section of one drawer or to scan all your literature and notes about the Kaiser plan. The Unix filesystem works in exactly the same way (as do most other hierarchical filesystems). Rather than having a heap of assorted files, files are organized into directories. A directory is really nothing more than a special kind of file that lists a bunch of other files (see Section 10.2). A directory can contain any number of files (although for performance reasons, it’s a good idea to keep the number of files in one directory relatively small — under 100, when you can). A directory can also contain other directories. Because a directory is nothing more than a special kind of file, directories also have names. At the top (the filesystem “tree” is really upside down) is a directory called the “root,” which has the special name / (pronounced “slash,” but never spelled out).

A hierarchical filesystem

Figure 1-2. A hierarchical filesystem

To locate any file, we can give a sequence of names, starting from the filesystem’s root, that shows the file’s exact position in the filesystem: we start with the root and then list the directories you go through to find the file, separating them by slashes. This is called a path. For examples, let’s look at the simple filesystem represented by Figure 1-3. The names /home/mkl/mystuff/stuff and /home/hun/publick/stuff both refer to files named stuff. However, these files are in different directories, so they are different files. The names home, hun, and so on are all names of directories. Complete paths like these are called “absolute paths.” There are shorter ways to refer to a file: relative paths (Section 1.16).

— ML

A Unix filesystem tree

Figure 1-3. A Unix filesystem tree

Your Home Directory

Microsoft Windows and the Mac OS have hierarchical filesystems (Section 1.14), much like those in Unix and other large systems. But there is an important difference. On many Windows and Mac systems, you start right at the “root” of the filesystem tree. In effect, you start with a blank slate and create subdirectories to organize your files.

A Unix system comes with an enormous filesystem tree already developed. When you log in, you start somewhere down in that tree, in a directory created for you by the system administrator (who may even be yourself, if you are administering your own system).

This directory — the one place in the filesystem that is your very own, to store your files (especially the shell setup files (Section 3.3) and rc files (Section 3.20) that you use to customize the rest of your environment) — is called your home directory.

Home directories were originally stored in a directory called /usr (and still are on some systems), but are now often stored in other directories, such as /home. Within the Linux Filesystem Hierarchy Standard (FHS), the home directory is always at /home, as configuration files are always in /etc and so on.

To change your current directory (Section 1.16) to your home, type cd with no pathname; the shell will assume you mean your home directory.

Within the Mac OS X environment, home is in the /Users/username directory by default.

— TOR

Making Pathnames

Pathnames locate a file (or directory, or any other object) in the Unix filesystem. As you read this article, refer to Figure 1-4. It’s a diagram of a (very) small part of a Unix filesystem.

Part of a Unix filesystem tree

Figure 1-4. Part of a Unix filesystem tree

Whenever you are using Unix, you have a current directory. By default, Unix looks for any mentioned files or directories within the current directory. That is, if you don’t give an absolute pathname (Section 1.14) (starting from the root, / ), Unix tries to look up files relative to the current directory. When you first log in, your current directory is your home directory (Section 1.15), which the system administrator will assign to you. It typically has a name like /u/mike or /home/mike. You can change your current directory by giving the cd command, followed by the name of a new directory (for example, cd /usr/bin). You can find out your current directory by giving the pwd (“print working directory”) command.

If your current directory is /home/mike and you give the command cat textfile, you are asking Unix to locate the file textfile within the directory /home/mike. This is equivalent to the absolute path /home/mike/textfile. If you give the command cat notes/textfile, you are asking Unix to locate the file textfile within the directory notes, within the current directory /home/mike.

A number of abbreviations help you to form relative pathnames more conveniently. You can use the abbreviation . (dot) to refer to the current working directory. You can use .. (dot dot) to refer to the parent of the current working directory. For example, if your current directory is /home/mike, ./textfile is the same as textfile, which is the same as /home/mike/textfile. The relative path ../gina/textfile is the same as /home/gina/textfile; .. moves up one level from /home/mike (to /home) and then searches for the directory gina and the file textfile.

You can use either the abbreviation ~ (tilde) or the environment variables $HOME or $LOGDIR, to refer to your home directory. In most shells, ~ name refers to the home directory of the user name. See Section 31.11.

Here’s a summary of the rules that Unix uses to interpret paths:

If the pathname begins with /

It is an absolute path, starting from the root.

If the pathname begins with ~ or with ~ name

Most shells turn it into an absolute pathname starting at your home directory (~) or at the home directory of the user name (~ name).

If the pathname does not begin with a /

The pathname is relative to the current directory. Two relative special cases use entries that are in every Unix directory:

  1. If the pathname begins with ./, the path is relative to the current directory, e.g., ./textfile, though this can also execute the file if it is given executable file permissions.

  2. If the pathname begins with ../, the path is relative to the parent of the current directory. For example, if your current directory is /home/mike/work, then ../src means /home/mike/src.

Section 10.2 explains where . and .. come from.

Note

The . and .. may appear at any point within a path. They mean “the current directory at this point in the path” and “the parent of the current directory at this point in the path.” You commonly see paths starting with ../../ (or more) to refer to the grandparent or great-grandparent of the current directory. However, they can appear at other places in a pathname as well. For example, /usr/ucb/./bin is the same as /usr/ucb/bin, and /usr/ucb/bin/../lib is the same as /usr/ucb/lib. Placing . or .. in the middle of a path may be helpful in building paths within shell scripts, but I have never seen them used in any other useful way.

—ML and JP

File Access Permissions

Under Unix, access to files is based on the concept of users and groups.

Every “user” on a system has a unique account with a unique login name and a unique UID (Section 24.3) (user ID number). It is possible, and sometimes convenient, to create accounts that are shared by groups of people. For example, in a transaction-processing application, all of the order-entry personnel might be assigned a common login name (as far as Unix is concerned, they only count as one user). In a research and development environment, certain administrative operations might be easier if members of a team shared the same account, in addition to having their own accounts. However, in most situations each person using the system has one and only one user ID, and vice versa.

Every user may be a member of one or more “groups.”[2] The user’s entry in the master password file (/etc/passwd (Section 22.3)) defines his “primary group membership.” The /etc/group (Section 49.6) file defines the groups that are available and can also assign other users to these groups as needed. For example, I am a member of three groups: staff, editors, and research. My primary group is staff; the group file says that I am also a member of the editors and research groups. We call editors and research my “secondary groups.” The system administrator is responsible for maintaining the group and passwd files. You don’t need to worry about them unless you’re administering your own system.

Every file belongs to one user and one group. When a file is first created, its owner is the user who created it; its group is the user’s primary group or the group of the directory in which it’s created. For example, all files I create are owned by the user mikel and the group staff. As the file’s owner, I am allowed to use the chgrp command to change the file’s group. On filesystems that don’t have quotas (Section 15.11), I can also use the chown command to change the file’s owner. (To change ownership on systems with quotas, see Section 50.15.) For example, to change the file data so that it is owned by the user george and the group others, I give the commands:

% chgrp others data
% chown george data

Warning

If you need to change both owner and group, change the group first! You won’t have permission to change the group after you aren’t the owner.

Some versions of chown can change both owner and group at the same time:

% chown george.others data

File access is based on a file’s user and group ownership and a set of access bits (commonly called the mode bits). When you try to access a file, you are put into one of three classes. You are either the file’s owner, a member of the file’s group, or an “other.” Three bits then determine whether you are allowed to read, write, or execute the file. So, as Figure 1-1 shows, there are a total of nine mode bits (three for each class) that set the basic access permissions.

— ML

The Superuser (Root)

In general, a process (Section 24.1) is a program that’s running: a shell, the ls command, the vi editor, and so on. In order to kill a process (Section 24.12), change its priority (Section 26.5), or manipulate it in any other way, you have to be the process’ owner (i.e., the user who started it). In order to delete a job from a print queue (Section 45.1), you must be the user who started it.

As you might guess, there needs to be a way to circumvent all of this security. Someone has to be able to kill runaway programs, modify the system’s files, and so on. Under Unix, a special user known as root (and commonly called the “superuser”) is allowed to do anything.

To become the superuser, you can either log in as root or use the su (Section 49.9) command. In this book, though, we’ll assume that you don’t have the superuser password. Almost all of what we describe can be done without becoming superuser.

— ML

When Is a File Not a File?

Unix differs from most operating systems in that it is file oriented. The designers of Unix decided that they could make the operating system much simpler if they treated everything as if it were a file. As far as Unix is concerned, disk drives, terminals, modems, network connections, etc. are all just files. Recent versions of Unix (such as Linux) have gone further: files can be pipes (FIFOs) (Section 43.11) and processes are files (Section 24.9). Like waves and particles in quantum physics, the boundary between files and the rest of the world can be extremely fine: whether you consider a disk a piece of hardware or a special kind of file depends primarily on your perspective and what you want to do with it.

Therefore, to understand Unix, you have to understand what files are. A file is nothing more than a stream of bytes — that is, an arbitrarily long string of bytes with no special structure. There are no special file structures and only a few special file types (for keeping track of disks and a few other purposes). The structure of any file is defined by the programs that use it, not by the Unix operating system.[3] You may hear users talk about file headers and so on, but these are defined by the applications that use the files, not by the Unix filesystem itself.

Unix programs do abide by one convention, however. Text files use a single newline character (linefeed) between lines of text, rather than the carriage return-linefeed combination used in Microsoft Windows or the carriage returns used in the Macintosh. This difference may cause problems when you bring files from other operating systems over to Unix. Windows files will often be littered with carriage returns (Ctrl-M), which are necessary for that operating system but superfluous for Unix. These carriage returns will look ugly if you try to edit or print the file and may confuse some Unix programs. Mac text files will appear to be one long line with no breaks. Of course, you can use Unix utilities to convert Mac and Windows files for Unix.

— ML

Scripting

Scripting languages and scripting applications differ from compiled languages and applications in that the application is interpreted as run rather than compiled into a machine-understandable format. You can use shell scripting for many of your scripting needs, but there are times when you’ll want to use something more sophisticated. Though not directly a part of a Unix system, most Unix installations come with the tools you need for this more complex scripting — Perl (Chapter 41), Python (Chapter 42), and Tcl.

These three scripting languages seem so prevelant within the Unix world that I think of them as the Unix Scripting Language Triumvirate. .

Perl is probably the granddaddy of scripting. Created by Larry Wall, this language is probably used more than any other for creating complex scripts to perform sophisticated functionality with Unix and other operating systems. The language is particularly noted for its ability to handle regular expressions, as well as working with files and other forms of I/O.

Python isn’t as widespread as Perl, but its popularity is growing. One reason it’s gaining popularity is that as a language, Python is more structured and a little more verbose than Perl, and therefore a little easier to read. In addition, according to its fans, Python has more object-oriented and data-manipulation features than the file-manipulation and regular-expression manipulation of Perl.

Tcl is particularly prevalent within Linux systems, though its use is widespread throughout all Unix systems. It’s popular because it’s simpler to learn than Perl and allows scripters to get up to speed more quickly than you can with Perl or Python. In addition, the language also has access to a very popular graphical user interface library called the Tk toolkit. You’ll rarely hear about Tcl without the associated Tk.

—TOR and SP

Unix Networking and Communications

Generally speaking, a network lets two or more computers communicate and work together. Partly because of the open design of Unix, a lot of networking development has been done in this operating system. Just as there are different versions of Unix, there are different ways and programs to use networks from Unix.

There’s an entire chapter devoted to Connectivity (Chapter 46), but for now, here’s a quick review of the major networking components.

The Internet

The Internet is a worldwide network of computers. Internet users can transfer files, log into other computers, and use a wide range of programs and services.

WWW

The World Wide Web is a set of information servers on the Internet. The servers are linked into a hypertext web of documents, graphics, sound, and more. Point-and-click browser programs turn that hypertext into an easy-to-use Internet interface. (For many people, the Web is the Internet. But Unix lets you do much more.)

mail

A Unix facility that’s been around for years, long before networking was common, is electronic mail. Users can send electronic memos, usually called email messages, between themselves. When you send email, your message waits for the other user to start his own mail program. System programs can send you mail to tell you about problems or give you information. You can send mail to programs, asking them for information. Worldwide mailing lists connect users into discussion groups.

ftp

The ftp program is one way to transfer files between your computer and another computer with TCP/IP, often over the Internet network, using the File Transfer Protocol (FTP).

UUCP

Unix-to-Unix Copy is a family of programs (uucp, uux, uulog, and others) for transferring files and email between computers. UUCP is usually used with modems over telephone lines and has been mostly superceded by Internet-type connections.

Usenet

Usenet isn’t exactly a network. It’s a collection of hundreds of thousands (millions?) of computers worldwide that exchange files called news articles. This “net news” system has thousands of interactive discussion groups — electronic bulletin boards — for discussing everything from technical topics to erotic art.

telnet

This utility logs you into a remote computer over a network (such as the Internet) using TCP/IP. You can work on the remote computer as if it were your local computer. The telnet program is available on many operating systems; telnet can log you into other operating systems from your Unix host and vice versa.

rsh

This starts a "remote shell” to run a command on a remote system without needing to log in interactively. If you don’t give a command, rsh acts like rlogin. This is often used to start remote X Window System (Section 1.22) programs whose display opens on your local system. Section 6.10 has examples — as well as details on problems you can have running rsh for any application.

ssh

ssh acts like rsh (and rlogin), but it makes a secure encrypted connection to the remote computer. It also can encrypt X Window System (Section 1.22) connections, as well as other types of connections, between hosts. The utility ssh-agent allows remote logins without typing a passphrase. We’ve included an entire chapter on ssh (Chapter 51).

rcp

This is a "remote cp" program for copying files between computers. It has the same command-line syntax as cp except that hostnames are added to the remote pathnames.

scp

This is a secure version of rcp that uses the ssh protocol. ssh-agent works here, too.

NFS

NFS isn’t a user utility. The Network FileSystem and related packages like NIS (the Network Information Service) let your system administrator mount remote computers’ filesystems onto your local computer. You can use the remote filesystem as easily as if it were on your local computer.

write

This sends messsages to another user’s screen. Two users can have a discussion with write.

talk

A more sophisticated program than write, talk splits the screen into two pieces and lets users type at the same time if they wish. talk can be used over networks, though not all versions of talk can talk to one another.

irc

Internet Relay Chat allows multiple users to carry on multiple discussions across the Internet and other networks. One popular IRC client is irc.

— JP

The X Window System

In 1988, an organization called the MIT (Massachusetts Institute of Technology) X Consortium was formed to promote and develop a vendor-neutral windowing system called the X Window System. (It was called “X” because it was a follow-on to a window system called “W” that was developed at Stanford University.) The organization eventually moved away from MIT and became known as the X Consortium. The XFree86 Project, Inc. is another major group developing X; they produce a freely redistributable version that’s used on Linux and other Unix-like systems such as Darwin.

A window system is a way of dividing up the large screen of a workstation into multiple virtual terminals, or windows. Each window can interact with a separate application program — or a single application can have many windows. While the “big win” is to have applications with point-and-click mouse-driven user interfaces, one of the most common applications is still a simple terminal emulator (xterm (Section 5.9)). X thus allows a workstation to display multiple simultaneous terminal sessions — which makes many of the standard Unix multitasking features such as job control less important because programs can all be running in the foreground in separate windows. X also runs on many kinds of hardware, and it lets you run a program on a remote computer (across a network) while the program’s windows are displayed on your local system. Because Unix systems also run on many kinds of hardware, this makes X a good match for Unix.

Unix boxes are, by default, character-based systems. GUI Communication with Unixsystems are added to facilitate ease of use, as well as to provide access to a great number of sophisticated applications. The Mac OS X, though, is already a GUI, built on the BSD-based Unix environment, Darwin.

Though Darwin doesn’t come with the X Window System, versions of X are available for Mac OS X..

—TOR and JP



[1] [Tim is keeping this article simple, as an illustration of how easy writing a shell program can be. If you’re writing this little script for general use, you can make it work like a filter (Section 1.5) by adding four or five more lines of code: a case (Section 35.10) or if (Section 35.13) statement that tests the number of command-line arguments. With no filename arguments, the script would simply run tr '\015' '\012'. — JP]

[2] In most newer Unix systems, users have the access privileges of all groups to which they belong, all at the same time. In other Unix systems, you use a command like newgrp (Section 48.6) to change the group to which you currently belong. Your system may even support both methods.

[3] Many executable files — programs — begin with a magic number. This is a special two-byte-long sequence that tells the kernel how to execute the file.

Get Unix Power Tools, 3rd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.