Bash And You

terminal

1 What is BaSH?

BaSH, or the “Bourne-Again SHell”, is a command line interpreter originally
written for the Unix operating system. It is an open source replacement for the
original Bourne shell. Bash commands look like this:

“BaSH” is generally stylized “bash”.

2 Basics

2.1 What is a shell?

A shell is a program that reads input by lines, interprets them as small
programs, and runs them in an environment that persists until the shell quits.

Traditionally shells have prompts so that you can see when the previous command
has finished, and when you can enter a new line of input. Any output from the
program will for the most part be printed before the next prompt appears. On
the homework server, the default shell is called tcsh and the prompt looks
like this before being customized:

Where the number at the end indicates how many lines of input you have entered
so far. For the purposes of this tutorial, however, I will be using just $ as
the prompt to simplify things. A a sample interaction in the shell might look
like this:

The command ls shows the contents of the current directory. That’s my home
folder!

Since the rest of the tutorial will explain bash, many ideas will not cross
over to tcsh. For that reason, I recommend running bash in your terminal,
like so:

You’ll notice that the prompt has changed. That’s because bash is just
another program, and can be run from inside tcsh.

2.2 Command line interaction vs. scripting

Bash can either be used interactively, like in a shell, or in a shell
script. For those of you who have never used a scripting language before:
instead of being compiled and then run, the programs are instead interpreted on
the fly.

With a script, the programmer has more editing flexibility and can re-run the
same combination of commands all at once with more ease. This is especially
useful when writing a script that takes input, like a “greeting” type program:

The first line of this program is called the “hashbang” or “shebang” line. It
indicates how the program should be processed and executed when run. The second
line is just a comment to indicate to you what the filename is. The fourth line
is the body of our actual program.

In bash, echo is a builtin function that prints each argument it gets,
separated by spaces. “But what is ‘$1’?”, you might ask. Well. Variables in
Bash start with a dollar sign, and $1 is a special variable. $1, $2,
$3, etc are special variables that contain the arguments (in order) that are
passed to a shell script. In C, you have an array and a number of arguments
(argv and argc, respectively). In Bash there is no such thing. In our case,
$1 will contain somebody’s name.

In order to run this program, we would first have to mark it as
executable. This change in file permissions is a security measure; it helps
specify who can do what to a particular file. The operations on a file, for
example, are read, write, and execute. What permissions does this file
have right now?

The farthest left field, -rw-r--r--, tells us the permissions on the
file. Each character gives some information about the permissions. The two
words after the number 1 tell us the owner and group to whom this file is
assigned.

The first character gives some information about the type of file. Since this
one is just a regular ol’ file (as opposed to a directory, socket, or pipe), it
doesn’t get a character.

The next three describes the permissions of the owner of the file (in this
case, me). I get read and write permissions on this file.

The second group of three characters describes the permissions of the group. In
this case, people in the group staff can read this file.

The last group of three describes the permissions of everyone else not me and
not in the group – they can also only read this file.

Let’s mark hello.sh as executable with chmod:

And check again the permissions of the file:

It looks like now everybody can read and execute this file, but only I can
write to it. If we wanted to only mark it as executable for me, however, we
should instead do:

Which would result in:

The u qualifier of the +x indicates that only the owner should be able to
execute. For group, the qualifier is g, and for other it is o. Similarly,
to remove a permission, use, for example, u-x.

Let’s run hello.sh:

Interesting! It printed nothing. Since we didn’t pass it an argument on the
command line, $1 contained just the empty string. To avoid things like this,
most command-line programs contain help pages that print when the command is
called the wrong way. Let’s try again with a name, as it’s intended to be
called:

Much better. While this particular script doesn’t demonstrate why writing a
full script is helpful, it does give a small and easy to digest example.

2.3 Command line flags

I will briefly explain command line flags in general. However, since the flags
vary quite a bit program to program and OS to OS, I will not attempt to
generalize.

Command line flags are indicators given to a program on the command line. They
are commonly used to switch a program into a certain mode, or set a certain
variable.

They can take a few forms, but the most common are the short form (like -n,
-a, -1, etc) and the long form (like --newline, --append, etc). Both
types can take arguments, and in fact most programs employ both types, with the
long forms having short equivalents (because programmers are lazy typists).

Note that the short form generally has one hyphen, and the long form has two.

Let me give a practical example. Imagine that we want echo to have an all
caps mode, to make it sound like we are yelling at people. Something like this,
perhaps:

Our rather arbitrary decision will convert all letters to capitals and convert
all periods to exclamation marks. Let’s also imagine a shorter version of this
flag, -y, so that we don’t have to type --yell every time:

Ah, much better.

In scripts, long-form arguments are generally preferred; they self-document
much better than short form arguments. I have often looked back on a bash
script and thought, “Wow, what the heck do rsync‘s -avz flags do?” I now
use --archive --verbose --compress instead.

3 Built-in features

There are a ton of other built-in features that I will only touch on
lightly. If you are interested, I encourage you to do more research on your
own.

3.1 Variables

Just as in other programming languages, Bash has variables. With Bash, however,
variables are not declared and are not defined with a particular type. For
example:

Note that this is a string, desplite a lack of explicit quotation. Quotes are
optional unless defining a string of more than one word. For example:

Also note that the equals sign and contents must be all tacked together with no
space in between.

Additionally, it is not possible to access a variable’s value by name alone; it
must be prepended with a $ (dollar sign):

Note that there is a newline before the next prompt starts. That is not part of
the contents of the variable; instead, it is appended by echo to make this
kind of thing more readable.

Variables can of course have numeric values as well:

Just note that it is not possible to do arithmetic as you would expect:

The shell and echo take the argument literally, so actually the numeric
values are represented as strings. For math, take a look at the command line
utility bc.

3.1.1 Exit codes

An exit code is a value returned back to the shell from a command that is
called. It’s very similar to what a function might return, except for two
constraints. This value only represents a range of errors (or lack thereof),
and must fall between 0 and 255.

Imagine we have a some program called makeitstopsnowing. When our program
finished, it would return 0 (if it had succeeded in stopping the snow) or some
other number (to indicate some kind of error).

Exit codes can be used conditonally. Imagine we have a program called
goswimming that we only want to call if we have made it stop snowing. We
could do so like this:

Because of short-circuit evaluation1,
goswimming is only executed if makeitstopsnowing succeeds.

3.2 I/O redirection

You may have seen what is called “I/O Redirection” in COMP 11 or COMP 15. It is
used in those classes to pass files as input to programs. For example:

In that example, the contents of the file numberList.txt are passed as
stdin, or standard input, to the program quickSort. This is useful when
giving large amounts of input by hand is impractical (as in a large list of
unsorted numbers).

Another way to pass the same input to quickSort is with a pipe:

In this case, the program cat is reading the file numberList.txt, printing
its output to stdout (standard output), and then the pipe (shown with the
vertical bar character) passes that output to quickSort‘s stdin.

In order to redirect output to a file, one can use the other angle bracket:

In this case, we pass the numbers to quickSort, sort them, and then (since
quickSort prints to stdout), pass the sorted numbers into a file called
sortedList.txt. Please note that this operator will both create new files and
overwrite the contents of existing files.

In order to append to a file, you can double the operator:

This will also create new files, but it will only append output to existing files.

Prepending to files is not possible with just this set of operators; instead,
it is generally advised to create temporary files and go from there.

4 Some commands of interest

Command Common use
ls List files
rm Delete files
cd Change directory
echo Print something
cat Show contents of file
emacs Text editor
vi / vim Text editor
which Find where a command lives
less Let user page through a file
gcc C compiler
g++ C++ compiler
make Scripted compilation
curl Download contents of webpage
ssh Remote login to server
rsync Copy files across computers

I found out which commands I used most with a chain of Bash commands taken
from SuperUser (a StackExchange site):

rank # uses % uses command
1 1529 16.2487% fg
2 1395 14.8247% git
3 746 7.92774% ls
4 436 4.63337% cd
5 394 4.18704% emacs
6 299 3.17747% curl
7 290 3.08183% brew
8 286 3.03932% make
9 213 2.26355% gcc
10 182 1.93411% rm
11 169 1.79596% guile
12 161 1.71095% jump
13 154 1.63656% ssh
14 114 1.21148% open
15 110 1.16897% cat
16 77 0.818278% heroku
17 75 0.797024% echo
18 70 0.743889% sudo
19 63 0.669501% pip
20 58 0.616366% scp

You can find the command here: http://superuser.com/a/250230/62154.


Maxwell Bernstein is a freshman majoring in Computer Science. He can be reached at enigma@bernsteinbear.com

Footnotes:

 

Leave a Reply

Your email address will not be published. Required fields are marked *