3. Bash

bash (bourne-again shell) is a Unix shell by GNU. It's the default shell of all common Linux distributions so chances that you get a bash on your server are quite big. To check if it's really bash you can use the command

$ echo $SHELL

Unix shells allow you to execute commands. For the people coming from a Microsoft background it's comparable to (though usually more powerful than) the DOS prompt.

Bash also provides more sophisticated functions to work effectively. For example there is a command history to easily access commands entered in the past. bash provides you with a job control to run different applications in the same shell. Additionally it has builtin flow control and other programming possibilities[1].

3.1. Executing programs

When you enter the name of a command to be executed, the shell variable (See section Shell Variables) PATH is searched until a path is found where a executable with that name is located. The single paths are separated by a colon. The content of this variable on my machine currently looks similar to this:

$ echo $PATH
/home/patrice/bin:/usr/local/bin:/usr/bin:/bin

Suppose you enter the command

$ touch test_file

touch is the command name and test_file is the argument. So the shell first searches a program named touch in the path. To do that it looks in /home/patrice/bin for an executable with that name. If there is one, it is executed. If there is none, the shell searches in /usr/local/bin. It continues like this for every entry in the path. If and only if no component of the path contains a file with that name, you get the error “command not found”. If one directory contains a file with that name, but it is not executable you get the error message “Permission denied”.

If you enter any directory information before the executable name, the shell doesn't try to locate the binary but assumes that you know better:

$ /bin/touch test_file
$ ../runit
$ ./testing

All of these have a path information in it. The first one always takes the touch binary from the directory /bin, no matter what the search path looks like. The next command looks in the parent directory for a executable named runit. The last one is especially interesting. It executes the program testing in the current directory. This syntax is used very ofted, because it frequently happens that you want to execute a binary in the current directory.

3.2. Shell variables

Shell variables can contain any value. The shell provides some variables to query the current status, while other shell variables can be set by the user to configure some settings or to be fetched back later. The variable names are case sensitive.

3.2.1. Query value

To insert the value of a shell variable at a place in the command line, just prepend the shell variable with a dollar sign[2]. For example this printss out your user name:

$ echo $USER

Sometimes you want to include variables in the middle of a word. Suppose this example:

$ echo $USERistesting

This doesn't print the expected “patriceistesting”. Instead you get no output at all. To fix that, you have to write curly braces around the variable:

$ echo ${USER}istesting

3.2.2. Setting value

To set the value of a shell variable, assign the value with an equal sign[3].

$ weather="sunny"
$ echo "The weather today is $weather"

This sets the variable for the current process, but any processes which is called from this one, doesn't get the value of this variable. If you want to make sure that the value gets passed to other processes you need to export it.

$ weather="sunny"
$ export weather
$ ./weather_program

Or with a bit less typing:

$ export weather="sunny"
$ ./weather_program

3.3. Working with the file system

3.3.3. listing files

The command ls lists the files and directories in the current directory if executed without any parameters. The parameter used most often is `-l', which shows a more detailed lists. The `-a' parameter is useful if you want to list all files while the default behavior is to not list hidden files[4].

If you want to get the details of only one file, use the command:

$ ls -l $FILENAME

This doesn't work for directories, because ls assumes you want to list the files in that directory. You can use the parameter `-d' to circumvent this problem. With that parameter, ls actually displays the details of the directory instead of the files in that folder.

$ ls -l -d $FOLDER

ls(1) lists all available command options.

3.4. Redirection

Every process has two output streams and one input stream:

With redirection it's possible to place the output in a file or read the input from a file. For example you can write the error output of a program to a log file.

3.5. Piping

Piping is a very important and powerful technique of Unix shells. Let's start with an example:

$ locate '*.txt' | less

This searches for any file with the extension “.txt” and then shows the result with less so that you can easily scroll through the output. By piping two processes together you essentially create a one-way communication channel between them. It redirects the output of the first process to the input of the second one. This is where redirection really gets powerful. For example you could also pipe the locate command above to the mail utility. An example says more than a thousand words:

$ find -atime +100 | mail systemservice@acme.com

This mails a list of all files that haven't been accessed for more than 100 days. This is a perfect example for a scheduled task.

You surely see the analogy to redirection, don't you? The previous example can also be rewritten this way:

$ find -atime +100 >tmp
$ mail systemservice@acme.com <tmp
$ rm tmp

But first it's more cumbersome, second it's less efficient and third you need to get a unique file name - especially if you execute this commands from a script.

3.6. Using the history

Every command line you enter is stored in the history. There are two common ways to access the history.

3.6.2. Bang

The second possibility is the exclamation point. It is described in the bash man page in the section “Event Designators”. The most important technique is the exclamation point followed by a string. This executes the previous command starting with that string.

$ !less

This example searches the history backwards for a command starting with “less” and executes it. So it basically opens the last file you have looked at with less. You can just enter two exclamation points to repeat the previously entered command[6].

If you aren't sure what command would be execute, append the string “:p” to the bang command. For example

$ !less:p

prints the previous command that started with the string “less”, but doesn't execute it yet. If it is what you want, use the bang-bang command to execute it, as bash is intelligent enough to move the command at the first position of the history.

3.7. Job Control

The bash allows you to execute several commands inside the same shell window. This has been very important in the past when no windowing was present. Nowadays it's a bit old fashioned but I still use it extensively. When accessing a server via ssh it's especially useful because opening a new session is usually a bit cumbersome.

Job control means that you can put a command in the background and later get it back. Suppose that you're in the bash man page and you want to try a command you have just read about. First press Ctrl+Z while reading the man page. This puts the man page in the background and gives you the shell back.

[1]+ Stopped man bash
$ 

Now you can enter your commands. When you're ready to continue reading the man page, just enter

$ fg

You can also put several jobs in the background. fg brings you to the last process that was active. Use the command jobs to print a list of the current jobs.

$ jobs
[1]   Stopped     man bash
[2]+  Stopped     vi test
[3]-  Stopped     man perl

The plus sign indicates the job you are returned to if you just enter fg. To specify the job you want to put in the foreground, add the job ID.

$ fg 1

So now you can continue to read the bash man page.

An alternative syntax uses the percent sign instead of `fg':

$ %1

Notes

[1]

Programming is not covered in this document, there are good existing HOWTOs for that.

[2]

Note, that this notation is also often used in Unix literature to mark a place where you can insert something. For example:

$ ls -l $FILENAME

This means, that you can replace te text “$FILENAME” with any filename you like.

[3]

Attention: Before and after the equal sign you must not use any spaces.

[4]

All files whose name starts with a dot are hidden.

[5]

Note that the file error.log also gets created/overwritten if stderr creates no output at all. This is always true for output redirection.

[6]

This is sometimes called bang-bang.