The Linux programming environment
This chapter will introduce you to Linux, a Unix-like operating system called Linux. Most people run Unix with a command-line interface provided by a shell. Each line typed to the shell tells it what program to run (the first word in the line) and what arguments to give it (remaining words). The interpretation of the arguments is up to the program.
The examples in this course assume you have bash, the Bourne-again shell written by the GNU project. Other shells behave similarly for basic commands.
The Unix filesystem
Most of what one does with Unix programs is manipulate the filesystem. Unix files are unstructured blobs of data whose names are given by paths consisting of a sequence of directory names separated by slashes: for example
/home/accts/some-user/cs223/hw1.c. At any time you are in a current working directory (type pwd to find out what it is and cd new-directory to change it). You can specify a file below the current working directory by giving just the last part of the pathname. The special directory names
.. can also be used to refer to the current directory and its parent. So /home/accts/some-user/cs223/hw1.c is just hw1.c or ./hw1.c if your current working directory is
cs223/hw1.c if your current working directory is
../cs223/hw1.c if your current working directory is
Unix command-line programs
Here are some handy Unix commands:
man program will show you the on-line documentation (the man page) for a program (e.g., try
man man or
man ls). Handy if you want to know what a program does. O
You can also use
man function to see documentation for standard library functions. The command
man -k string will search for man pages whose titles contain string.
Sometimes there is more than one man page with the same name. In this case
man -k will distingiush them by different manual section numbers, e.g.,
printf (1) (a shell command) vs.
printf (3) (a library routine). To get a man page from a specific section, use
man section name, e.g.
man 3 printf.
ls lists all the files in the current directory. Some useful variants:
ls /some/other/dir; list files in that directory instead.
ls -l; long output format showing modification dates and owners.
mkdir dir will create a new directory in the current directory named
rmdir dir deletes a directory. It only works on directories that contain no files.
cd dir changes the current working directory. With no arguments,
cd changes back to your home directory.
pwd (“print working directory”) shows what your current directory is.
mv old-name new-name changes the name of a file. You can also use this to move files between directories.
cp old-name new-name makes a copy of a file.
rm file deletes a file. Deleted files cannot be recovered. Use this command carefully.
chmod changes the permissions on a file or directory. See the man page for the full details of how this works. Here are some common
chmod 644 file; owner can read or write the file, others can only read it.
chmod 600 file; owner can read or write the file, others can’t do anything with it.
chmod 755 file; owner can read, write, or execute the file, others can read or execute it. This is typically used for programs or for directories (where the execute bit has the special meaning of letting somebody find files in the directory).
chmod 700 file; owner can read, write, or execute the file, others can’t do anything with it.
Stopping and interrupting programs
Sometimes you may have a running program that won’t die.
There are various control-key combinations you can type at a terminal window to interrupt or stop a running program.
Interrupt the process. Many processes (including any program you write unless you trap SIGINT using the
sigaction system call) will die instantly when you do this. Some won’t.
Suspend the process. This will leave a stopped process lying around. Type
jobs to list all your stopped processes,
fg to restart the last process (or
fg %1 to start process
bg to keep running the stopped process in the background,
kill %1 to attempt to end process
kill -KILL %1 to end process
%1 even if it is intercepting normal kills.
Send end-of-file to the process. Useful if you are typing test input to a process that expects to get EOF eventually or writing programs using
cat > program.c (not really recommended). For test input, you are often better putting it into a file and using input redirection (
./program < test-input-file); this way you can redo the test after you fix the bugs it reveals.
Quit the process. Sends a SIGQUIT, which asks a process to quit and dump core. Mostly useful if ctrl-C and ctrl-Z don’t work.
If you have a runaway process that you can’t get rid of otherwise, you can use
ps g to get a list of all your processes and their process ids. The
kill command can then be used on the offending process, e.g.
kill -KILL 6666 if your evil process has process id 6666. Sometimes the
killall command can simplify this procedure, e.g.
killall -KILL evil halts all process with command name
Running your own programs
If you compile your own program, you will need to prefix it with
./ on the command line to tell the shell that you want to run a program in the current directory (called ‘
.’) instead of one of the standard system directories. So for example, if I’ve just built a program called
count, I can run it by typing
Here the “
$ ” is standing in for whatever your prompt looks like; you should not type it.
Any words after the program name (separated by whitespace—spaces and/or tabs) are passed in as arguments to the program. Sometimes you may wish to pass more than one word as a single argument. You can do so by wrapping the argument in single quotes, as in
$ ./count 'this is the first argument' 'this is the second argument'
Redirecting input and output
Some programs take input from standard input (typically the terminal). If you are doing a lot of testing, you will quickly become tired of typing test input at your program. You can tell the shell to redirect standard input from a file by putting the file name after a
< symbol, like this:
$ ./count < huge-input-file
A ‘>’ symbol is used to redirect standard output, in case you don’t want to read it as it flies by on your screen:
$ ./count < huge-input-file > huger-output-file
A useful file for both input and output is the special file
/dev/null. As input, it looks like an empty file. As output, it eats any characters sent to it:
$ ./sensory-deprivation-experiment < /dev/null > /dev/null
You can also pipe programs together, connecting the output of one to the input of the next. Good programs to put at the end of a pipe are
head (eats all but the first ten lines),
tail (eats all but the last ten lines),
more (lets you page through the output by hitting the space bar, and
tee (shows you the output but also saves a copy to a file). A typical command might be something like
./spew | more or
./slow-but-boring | tee boring-output. Pipes can consist of a long train of programs, each of which processes the output of the previous one and supplies the input to the next. A typical case might be:
$ ./do-many-experiments | sort | uniq -c | sort -nr
./do-many-experiments gives the output of one experiment on each line, produces a list of distinct experimental outputs sorted by decreasing frequency. Pipes like this can often substitute for hours of real programming.
To write your programs, you will need to use a text editor, preferably one that knows enough about C to provide tools like automatic indentation and syntax highlighting. There are two reasonable text editors:
vim (see: vim faqs)(which can also be run as
vi). Emacs and Vi have been the two contenders for the One True Editor since the 1970s—if you learn one (or both) you will be able to use the resulting skills everywhere. My personal preference is to use Vi, but Emacs has the advantage of using the same editing commands as the shell and
gdb command-line interfaces.
If you are not editing directly from the terminal, you have more options. Some other popular text editors that work well with C are VS Code, Atom, and Sublime Text. The main downside to these editors is that they are relatively new, and so they don’t necessarily show up everywhere the way Emacs or Vi will. The other downside is that their relative novelty means that they won’t necessarily have the same longevity as your grandfather’s text editor: by the time you read this, there is a reasonably good chance that one or more of these popular editors is no longer very popular. But you should feel free to use whatever you are comfortable with as long as it works.
Writing C programs with Emacs
To start Emacs, type
emacs at the command line. If you have never used Emacs before, you should immediately type
C-h t (this means hold down the Control key, type
h, then type
t without holding down the Control key). This will pop you into the Emacs built-in tutorial.
My favorite Emacs commands
C-x means hold down Control and press
M-x means hold down Alt (Emacs calls it “Meta”) and press
M-x you can also hit Esc and then
Get help. Everything you could possibly want to know about Emacs is available through this command. Some common versions:
C-h t puts up the tutorial,
C-h b lists every command available in the current mode,
C-h k tells you what a particular sequence of keystrokes does, and
C-h l tells you what the last 50 or so characters you typed were (handy if Emacs just garbled your file and you want to know what command to avoid in the future).
Undo. Undoes the last change you made to the current buffer. Type it again to undo more things. A lifesaver. Note that it can only undo back to the time you first loaded the file into Emacs—if you want to be able to back out of bigger changes, use
git (described below).
Save. Saves changes to the current buffer out to its file on disk.
Edit a different file.
Quit out of Emacs. This will ask you if you want to save any buffers that have been modified. You probably want to answer yes (
y) for each one, but you can answer no (
n) if you changed some file inside Emacs but want to throw the changes away.
Go forward one character.
Go back one character.
Go to the next line.
Go to the previous line.
Go to the beginning of the line.
Delete the rest of the line starting with the current position. Useful Emacs idiom:
“Yank.” Get back what you just deleted.
Re-indent the current line. In C mode this will indent the line according to Emacs’s notion of how C should be indented.
Compile a program. This will ask you if you want to save out any unsaved buffers and then run a compile command of your choice (see the section on compiling programs below). The exciting thing about
M-x compile is that if your program has errors in it, you can type
C-x ` to jump to the next error, or at least where
gcc thinks the next error is.
Using Vi instead of Emacs
If you don’t find yourself liking Emacs very much, you might want to try Vim instead. Vim is a vastly enhanced reimplementation of the classic
vi editor, which I personally find easier to use than Emacs. Type
vimtutor to run the tutorial.
One annoying feature of Vim is that it is hard to figure out how to quit. If you don’t mind losing all of your changes, you can always get out by hitting the Escape key a few times and then typing ~~~\\\ :qa!\\\ ~~~
To run Vim, type
vim filename from the command line. Or you can use the graphical version
gvim, which pops up its own window.
Vim is a modal editor, meaning that at any time you are in one of several modes (normal mode, insert mode, replace mode, operator-pending mode, etc.), and the interpretation of keystrokes depends on which mode you are in. So typing
jjjj in normal mode moves the cursor down four lines, while typing
jjjj in insert mode inserts the string
jjjj at the current position. Most of the time you will be in either normal mode or insert mode. There is also a command mode entered by hitting
: that lets you type longer commands, similar to the Unix command-line or M-x in Emacs.
My favorite Vim commands
Get help. (Hit Enter at the end of any command that starts with a colon.) Escape
Get out of whatever strange mode you are in and go back to normal mode. You will need to use this whenever you are done typing code and want to get back to typing commands.
Enter insert mode. You will need to do this to type anything. The command
a also enters insert mode, but puts new text after the current cursor position instead of before it.
Undo. Undoes the last change you made to the current buffer. Type it again to undo more things. If you undid something by mistake, c-
R) will redo the last undo (and can also be repeated).
Write the current file to disk. Use
:w filename to write it to
:wa to write all files that you have modified. The command
ZZ does the same thing without having to hit Enter at the end.
Edit a different file.
Quit. Vi will refuse to do this if you have unwritten files. See
:wa for how to fix this, or use
:q! if you want to throw away your changes and quit anyway. The shortcuts
:wq do a write of the current file followed by quitting.
h, j, k, l
Move the cursor left, down, up, or right. You can also use the arrow keys (in both normal mode and insert mode).
Delete the current character.
Delete to end of line.
Delete all of the current line. This is a special case of a more general
d command. If you precede it with a number, you can delete multiple lines:
5dd deletes the next 5 lines. If you replace the second
d with a motion command, you delete until wherever you land:
d$ deletes to end of line (
D is faster),
dj deletes this line and the line after it,
d% deletes the next matching group of parentheses/braces/brackets and whatever is between them,
dG deletes to end of file—there are many possibilities. All of these save what you deleted into register
"" so you can get them back with
dd, but only saves the line to register
"" and doesn’t delete it. (Think copy). All the variants of
dd work with
Pull whatever is in register
"". (Think paste).
« and »
Outdent or indent the current line one tab stop.
make in the current directory. You can also give it arguments, e.g.,
:make test. Use
:cn to go to the next error if you get errors.
Run a command, e.g.,
:! echo hello world or
:! gdb myprogram. Returns to Vim when the command exits (control-C can sometimes be helpful if your command isn’t exiting when it should). This works best if you ran Vim from a shell window; it doesn’t work very well if Vim is running in its own window.
control-P and control-N
These are completion commands that attempt to expand a partial word to something it matches elsewhere in the buffer. So if you are a good person and have named a variable
informativeVariableName instead of
ivn, you can avoid having to type the entire word by typing
control-O and control-I
Jump to the last cursor position before a big move / back to the place you jumped from.
Get out of insert mode!
Unlike Emacs, Vim’s default settings are not very good for editing C programs. You can fix this by creating a file called
.vimrc in your home directory with the following commands:
filetype plugin on
filetype indent on
(You can download this file by clicking on the link.)
In Vim, you can type e.g.
:help backup to find out what each setting does. Note that because
.vimrc starts with a
., it won’t be visible to
ls unless you use
ls -a or
In this chapter, we introduced you to Linux, the
bash shell, important shell commands and couple of very popular text editors. In the next chapter, we’ll go through how to compile and debug C programs.