Mike’s Web Site & Blog

No Subtitle Exists

GNU Bash Usage 101

For the really in-depth stuff, read the GNU Bash Reference Manual, or even just bash(1), which is stupidly detailed. This is intended to be a quick introduction; for more advanced things like using the shell for automation through scripting, additional reading will be required.

The Shell Prompt

When a command-line system wants you to do something, it will prompt you, by issuing a command-line prompt on the screen. While the exact form of the prompt differs between systems, it often starts out with something simple, such as the following:

[mbt@borgripper ~]$ _

Within square brackets appears my username and the system’s hostname, as well as the directory that I am in (in this case, ~, which means $HOME, which for me is /home/mbt). The underscore represents where the terminal’s blinking cursor would be located.

The shell has the single fundamental job of taking user input and acting on it. User input can happen at the command line itself, or in the form of shell scripts, which are used to perform complex jobs using a single command.

Running Commands

Commands on UNIX systems are simply executable binary programs or scripts (including shell scripts). Such files are marked as executable on the filesystem, meaning that you can run them by typing the path to the command.

For example, the ls(1) program is often installed in /usr/bin, so it can be run as follows:

[mbt@borgripper ~]$ /usr/bin/ls
[ ... output from file listing omitted ...]

Of course, it would be inconvenient to type /usr/bin/ls every time, so the shell has the notion of the PATH. The PATH is a shell variable that holds a list of directories. When you type a command name that does not include any path information, the shell will search these directories (in order) until one of the following happens:

  • The shell finds the executable file, and asks the OS to run it.
  • The shell does not find the executable file and returns an error.
  • The shell finds a matching file, but the file is not executable and so it returns an error.

This means that:

[mbt@borgripper ~]$ ls
[ ... output from file listing omitted ...]

… will work as long as ls(1) is found in one of the directories present in the PATH variable, and is executable.

As you’ll see later, variables play a major role in the shell. However, they are complex enough that we’ll only worry about the PATH variable for now.

“Pipelines”, a.k.a. The UNIX Way

One of the most powerful features of modern shells is the ability to create complex “one-liner” scripts that perform larger tasks than any of the single commands could do on its own.

For example:

[mbt@borgripper ~]$ cat /proc/cpuinfo | grep ^processor | wc -l
32

The cat(1), grep(1), and wc(1) commands are each single-purpose commands, but together that pipeline results in the answer to the question “How many CPUs are available on this system?”

This works by taking the output from the cat(1) command and piping it into the grep(1) command, and taking the grep(1) command’s output and piping that into the wc(1) command.

The result is that grep(1) filters out all of the lines except those that begin with the word “processor”, and wc(1) then counts how many lines are output. The knowledge that the answer is correct, of course, depends on the knowledge that the special file /proc/cpuinfo will always be laid out in a manner which allows this command to operate successfully.

A pipeline can be thought of as a “connection” from one program’s standard output to another program’s standard input (which, along with standard error are known as a program’s stdio).

Shell Variables

There are two types of variables in the shell:

  • Local, or non-exported, shell variables, and
  • Environment, or exported, shell variables.

Environment variables are visible to programs executed by the shell; local variables are not.

Viewing a Variable

To look at the value of a variable, the following command can be given at the shell prompt:

[mbt@borgripper ~]$ printf "%s\n" "$PATH"
/home/mbt/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin

I used printf(1) instead of echo(1) in the example, because the use of echo can lead to problems.

Setting a Variable

To set the value of a variable, the following command can be given at the shell prompt:

[mbt@borgripper ~]$ VARIABLENAME='a string value'
[mbt@borgripper ~]$ _

To export that variable into the environment, do it like this:

[mbt@borgripper ~]$ VARIABLENAME='a string value'
[mbt@borgripper ~]$ export VARIABLENAME
[mbt@borgripper ~]$ _

Return Codes

When the shell has finished running a single statement, a numeric result is returned. Conventionally, the result zero means “success,” which non-zero return codes indicate “failure” of some sort or another.

The return value of the previously evaluated statement is stored in the special shell variable ?, which can be inspected as follows:

[mbt@borgripper ~]$ printf "%s\n" "$?"
0
[mbt@borgripper ~]$ _

Tab Completion

Often, you can press the TAB key on the keyboard once or twice and the shell will “help you out” by showing a list of possibilities. For example:

[mbt@borgripper ~]$ ls<TAB><TAB>
ls          lsblk       lsinitcpio  lskat   
lslogins    lsmod       lspci       lsusb       
lsattr      lscpu       lsipc       lslocks     
lsmem       lsns        lspcmcia    lsusb.py    
[mbt@borgripper ~]$ ls_

In this way, you can determine what programs are available, one prefix at a time.

Sections

Thank you for stopping by!

If you liked this article you can give a tip or become a patron. It helps pay my bills and keep me writing.