optipng 0.7.5 running under Bash 4.3.39 in LXTerminal 0.2.0

OptiPNG 0.7.5 running under Bash 4.3.39 in LXTerminal 0.2.0

NOTE:

  • Links to Wiki articles are provided in this post for those that wish to learn more, but it is important to note that I cannot guarantee their accuracy.

Bash, also known as the Bourne-again shell, is a Unix shell and command language, that is developed as part of the GNU Project. Along with the Linux kernel and package management system, I would rank Bash as one of the three most important components of a Sabayon Linux system. Without it or some other Unix shell in its place, one’s ability to interact one’s system would be very limited and difficult.

It was originally developed by Brian J. Fox in 1989 and has since become the most widely used Unix shell, with the vast majority of Linux distributions using it as their default command shell (only notable exception I have come across is Deepin, which uses Zsh) and since the release of 10.3 in October 2003 is has replaced tcsh as the default command shell for OS X.

In this post I will give some necessary background on Bash and its predecessor, the Bourne shell, as well as some basic scripting in Bash, some applications, etc. It is important to remember I am not an expert at Bash or Bash scripting, I have even had doubts I could even write an entire post on Bash scripting. It is important to note too that this post is nowhere near comprehensive on this topic, as the only type of text I, or anyone, could write that would be comprehensive on this topic would be an entire several-hundred page book, not a dozen-or-so-page blog post. This post just gives you some of the tools to do many of the basic things a novice or intermediate user of Sabayon would like to be able to do with Bash.

Background

Brian J. Fox (1959-), the original developer of Bash

Brian J. Fox (1959-), the original developer of Bash

The development of Bash began in January 1988, when Richard Stallman, the founder of the GNU Project and the Free Software Foundation (FSF), became dissatisfied with the previous author of the GNU shell’s failure to meet the required deadlines and decided, instead, to get FSF staff member, Brian J. Fox to write a free imitation of the Bourne Shell.1 Later in June 1989, the first public release of Bash was made, 0.99 (which was a beta release) and until mid 1992 (when Bash 1.12 was released), Fox remained the lead developer of Bash.2 When Fox left the FSF in mid 1992, Chet Ramey took over responsibility for Bash’s development, which he has kept to this very day.3

Other Unix Shells

The Bourne Shell was one of the first official Unix shells to be developed and was first developed in 1977. I am using the phrasing “official Unix shells”, to draw attention to the fact that the Bourne Shell was developed at Bell Labs for use by Research Unix, which was the original Unix system. The Bourne Shell is named after Stephen Bourne, its original developer.

While Bash was originally developed as a free “imitation” of the Bourne Shell, it also has features that it borrows from other Unix shells: including the C shell and the Korn shell. The C shell (csh) is a Unix shell that was originally developed by Bill Joy — the author of the Vi text editor (which is a direct ancestor of Vim) and was first released in 1978 (and is still under active development today). Its chief distinguishing feature is that its syntax is similar to that of the C programming language. A notable descendent of C shell that is also widely used today, is tcsh (the TENEX C Shell), which before release 10.3 was the default shell of OS X. The Korn shell (ksh) was one of the Unix shells developed at Bell Labs for Research Unix, although unlike most other of the original Unix shells it is still under active development today.

Along with these shells, another free Unix shell that has gained notoriety, that I feel is worthwhile mentioning is the Z shell (Zsh). Zsh was first released by Paul Falstad in 1990 and at the time Falstad was a student at Princeton University. Since then Zsh’s development has become coordinated by Peter Stephenson. What is notable about Zsh, is how feature-packed it is. It has many of the same features as Bash, but it also has spelling-correction, easier customizability and a few other features that Bash lacks.

All free Unix shells that are available for Gentoo or Sabayon systems are located in the category of app-shells within the Entropy Store, Portage Tree and Gentoo Portage Overlays. To show them all from the command-line run:

user $  eix -C -c “app-shells”

Changing Unix Shells

On Unix/Unix-like platforms it is possible to change your login shell using the chsh command. For example, to change your login shell to Zsh (assuming it is installed), run:

user $  chsh -s /bin/zsh

and then reboot.

Definitions

A natural question, that is asked by everyone, that is introduced to Unix shells, is “What is a Unix shell, exactly?” While this question sounds simple and straightforward, the answer is difficult to put into words, without it being either too generalized and vague, or too focused on specific examples. So I am going to air on the side of generalization and say that a Unix shell, is a command-line interpreter (CLI) that provides a familiar interface by which users can interact with the Unix4 system. Take the example of Bash, which is started whenever you open up a terminal emulator (TEE) or start tty1 (with Ctrl+Alt+F1) within most Linux systems, provided you have not set your default shell to something other than Bash. It interprets every command you type into the TEE or tty1 and can make changes to your system, accordingly. On most Linux systems, Unix shells are stored in the file directory /bin. You can list them all by issuing the command:

root #  cat /etc/shells

for me, for example, on my Sabayon machine this gives the output:

Bash and other Unix shells, have their own unique syntax or language (that is, how commands are passed onto Bash and other Unix shells), although most text editors (TEs) group all shell scripting languages together and call their collective syntax or language, “Shell script” or even just “sh”. Examples of such TEs include: Atom, gedit and SciTE. They can do this without a problem in most cases because Unix shells share quite a lot of their syntax with one another.

Another important concept, for one to understand in order for the rest of this post to make any sort of sense, is that of a script. Scripts are programs that can be interpreted from within a run-time environment (RTE) and they automate the execution of tasks that would otherwise have to be performed manually, one-by-one, by a human operator. In the case of shell scripts, including Bash scripts, the RTE in which the script is interpreted is the Unix shell.

Bash and Files

Bash scripts usually have the file extension of .sh, although some have no file extension. When Bash is started as an interactive, non-login shell (for example, from within a TEE) it first reads ~/.bashrc. When it is started as an interactive, login shell (like when it is started within tty1) it first reads /etc/profile, ~/.bash_profile, ~/.bash_login and ~/.profile. Commands executed in Bash are also recorded in ~/.bash_history. Commands interpreted by Bash are case-sensitive.

Basic Syntax

The Bash syntax has several distinct components, which can be classed as keywords and special characters, bulletins, variables, functions, tests and conditionals.

Keywords and Special Characters

Keywords and special characters (KSCs) are an important concept to understand, they are words, or symbols, that have a special, set meaning when scripting in Bash. Examples are listed in Table 1.

Table 1: Some Keywords and Special Characters Permitted in Bash
KSC Meaning, or usage Example(s)
{...}
function
Used to define functions. Curly braces can also be used to just group lines of code together.
[...]
[[...]]
Used for tests, double square brackets are only available in more advanced Unix shells such as Bash, ksh and Zsh.
tests whether the input variable, $1 exists.
# Whatever follows is interpreted by Bash, as a comment, for human operators to read but to be left uninterpreted by Bash.
! Returns the reciprocal (opposite) or negates of what follows it.
(which returns 0 (true) if the variable X does not equal 3, or 1 if it is equal to 3).
$ Evaluates what comes after it, such as a mathematical expression in double square brackets. echo $[3 * 2] returns 6.
| This is called a pipe and it sends the output of a command through another. For example, A | B does A and sends its output through B. The following example downloads the source code tarball of the 1.1.0 release of Atom and pipes it through tar and gzip to decompress it.5
; Allows several commands to be executed on the same line.
~ Denotes the home directory. For example, as my username is fusion809 on my Sabayon machine, my home directory is /home/fusion809.
takes one to current user’s home directory. If it is run as root it will take one to one’s /root.
- Can be used as the arithmetic operator, minus, or as the previous working directory.
takes one to one’s previous working directory.
* Wildcard operator, can take on any value. Can also be used for multiplication. If you have a directory, ~/VirtualBox on your machine and no others starting with the prefix ~/Virtual then:

should change your current working directory to ~/VirtualBox.
. Serves as an equivalent to the source bulletin and as an equivalent to pwd As source (the following will execute every file with the extension .sh in the ~/Shell directory):

whereas as pwd:

which causes no change in current directory.
.. Denotes the parent directory If I am working in the ~/Shell directory, and run:

my present working directory (pwd) would then be ~, my home directory.
&& Executes subsequent commands, provided the preceding command(s) were executed without error. For example, A && B does A and then B, provided that A is executed without error. While A && B && C would do A, then if A returns no error, it would perform B and if A and B ran without error it would then run C.
case
esac
Conditional statement, checking whether inputs match. case starts them and esac ends them.
do
done
for
Used in for loops. for begins the loop, do enacts commands and done and finishes the loop.
elif
else
fi
if
then
Used in if conditionals.
in Used when dealing with lists This script should, if passed an argument open Atom to ~/Shell/$1.sh, otherwise ask the user to select from the list of shell scripts in ~/Shell of which one to open in Atom.
select Gets users to select from a list of options.

until, while and time are some other keywords that are not mentioned there, as I do not know enough about them to really comment on them. Keywords can be used as variables but I would not advise this, as this can quite easily become confusing.

Variables

Bash variables are defined using equal signs. They can be made global (making them available for all processes) or local (making them available just for the script at hand). Local variables are defined by just using an equal sign, for example:

PYTHONPATH=/usr/bin/python

while to define this variable globally, one would run:

export PYTHONPATH=/usr/bin/python

Bulletins

Several Bash commands (or bulletins) exist and some (but by no stretch of the imagination all — I do not even understand them all!) basic ones are explained in Table 2. It is worthwhile noting that all these commands are purely Bash commands, by this I mean, they do not call any command-line programs to do their work for them. See many commands you will see in Bash scripts are not Bash commands, per se, rather they are commands that use another command-line program such as mv or pwd to do the work, but they can be run from within Bash. Many of these programs are also borrowed from the GNU Project, namely its core utilities package (sys-apps/coreutils) and are stored in either /usr/bin/ or /bin/, directories.

Table 2: Some Basic Bulletins
Command Meaning Examples Manpage (HTML)
alias Set a synonym for a command or function alias.1p.html
cd Change directory.
changes one’s directory to /home/username/Documents.
cd.1p.html
date Outputs the date. Inputs/variables can be used to set the timezone and the format of the date given. This gives my local date and time in my preferred format:
date.1.html
export Set variables provided to it as environment, or global, variables. export.1p.html
history Outputs Bash history.
should show the last ten commands executed with Bash.
history.3.html
source Execute script(s) provided to it.
runs the ~/.bashrc script.
source.n.html

Tests

Tests are essential for conditionals. As their name suggests, they test to see whether or not a condition is satisfied. If the condition is satisfied they return 0, while if the condition is unsatisfied they return 1. Square brackets (which are a bulletin, by-the-way), [...], are used for tests, although double square brackets ([[...]]) can also be used for this purpose since Bash 2.02. The difference, from what I can tell, between single and double square brackets is that double square brackets allow one to perform more advanced tests than single square brackets. Single square brackets are also POSIX compliant and are found on all Unix shells.6

Conditionals

In Bash scripts conditionals use the output of a test and perform an action accordingly. Conditionals usually involve at least one of the following keywords: case, if, else, elseif and fi.

Functions

Functions are essentially convenient ways we can group pieces of code together, so as to give them order and make them more logical. Quite often functions are designed to take input and use it to generate an output, or to perform a task, although some functions require no input. All Bash functions share two main things in common: the use of the word “function” and the fact the function’s contents are contained within curly braces {...}.

Loops

Loops (which involve the for keyword), in Bash scripts, are used to automate the performing of tedious tasks that are sufficiently similar to one another.

Selectors

Selectors (marked by the select keyword) gives users choices as to which input(s) the rest of the selector block uses.

Applications

The primary value of Bash scripts is to automate tasks that would otherwise have to be done, over a longer time-frame by a human operator. I personally use shell scripts to make my life, when I am at the command-line, easier.

In my ~/.bashrc file I have links to several shell scripts stored in my ~/Shell directory. Both my ~/.bashrc and the shell scripts in my ~/Shell directory can be found at this GitHub repository. Here is my current ~/.bashrc file:7

I have at least three dozen functions I have defined in shell scripts located in the ~/Shell directory, but here I will mention some of the more interesting, or useful ones for Sabayon users, in general.

Interesting Scripts8

You may have noticed that I am hosting HTML versions of several Linux man pages within the /man subdomain of this blog. I generate them using a function contained within ~/Shell/man.sh called manhtml. For example, to generate emerge.1.html I ran user $  manhtml 1 emerge. Here are the contents of ~/Shell/man.sh (showing all the contents as manhtml depends on other functions to work):

while here is a function I created to help me install Moksha themes (it appears differently in my ~/Shell/other.sh file, as this form is mostly to walk you through how it works):

to install a new Moksha theme you would run user $  theme <THEME> where <THEME> is, of course, the theme’s name (how they appear in their respective GitHub repo’s URL).

Useful Functions for Sabayon Users

The following are some functions that, depending on how you operate on Sabayon, may be helpful.

Entropy

The following are taken from ~/Shell/equo.sh and they are functions (with aliases for said functions) that essentially automate some common actions one may perform with Entropy. They are not all the lines of code in equo.sh, they merely represent some of the more commonly-used codes. It is important to note some of these functions need not be defined as functions, they could instead be defined as aliases (using alias NAME=CODE where NAME is the function’s name and CODE is what is between the curly brackets).

Layman/Portage

Here are some lines from my emerge.sh script.

Free Help Resources

Further Reading

NOTE: All the following links are to free PDFs

Footnotes

  1. Source: email from 1987
  2. Source: Chet Ramey’s Scribd document
  3. Source: Bash Webpage
  4. Or Unix-like, in the case of Linux distributions such as Sabayon
  5. Note, I previously did not know how to pipe the output of wget through tar until I asked this question at Unix & Linux StackExchange. The defining of an ATOM variable (instead of just combining it into the second line) is mostly just for space restrictions within this table
  6. Source: Server Fault
  7. The for loop I got from the answers to this question at Unix & Linux SE
  8. Which is in the eye of the beholder of course, you may not find these interesting at all
  9. Its general topic is programming, so it is suitable for shell script-related questions. I have asked two questions there relating to shell script, as of 31 October 2015, both were resolved within an hour.
  10. As of 31 October 2015 I have asked 8 questions relating to shell scripts there and seven have been answered. Each of those that have been answered were resolved (that is, given an answer that solved whatever problem I had) within a day of me asking them.