LINUX BASH SHELL SCRIPT BASICS Part 3:
PUTTING TEXT ON THE SCREEN WITH ECHO AND HERE DOCUMENTS
There are several ways of putting text on the screen for users to read. The simplest is to use the echo command for each line like so:
echo “President Lincoln’s Gettysburg Address”
echo “Fourscore and seven years ago our fathers brought forth,”
echo “on this continent, a new nation, conceived in liberty, and”
echo “dedicated to the proposition that all men are created equal.”
echo “Now we are engaged in a great civil war, testing whether that”
echo “nation, or any nation so conceived, and so dedicated, can long”
echo “endure. We are met on a great battle-field of that war.”
Notice that echo with no text after it simply creates a new empty line. This works but gets cumbersome after just a few lines. Another way to do the same thing is to use one echo command and put the block of text between quotes like so:
echo “President Lincoln’s Gettysburg Address
Fourscore and seven years ago our fathers brought forth,
on this continent, a new nation, conceived in liberty, and
dedicated to the proposition that all men are created equal.
Now we are engaged in a great civil war, testing whether that
nation, or any nation so conceived, and so dedicated, can long
endure. We are met on a great battle-field of that war.
You can opt to add escape codes to echo to enable new lines and colors in conjunction with other utilities like tput. Adding the string $’\n’$ to the first line will add a new line before the text like this:
echo $’\n’$”This text will print on the screen with a blank line above it.”
While the echo command works nicely for single lines and small blocks of text, it can render unpredictable results, especially if there are characters in the text that the shell might see as commands. Here documents are more reliable and easier to work with for large pages of text or tightly formatted text like you’d want to use for menus. You must use some text display utility like cat to show here documents on the screen. You can also use more sophisticated pagers and text editors as well. The basic format of a here document looks like this:
cat << _EOF_ # Text below this command up to _EOF_ will be printed on screen.
President Lincoln’s Gettysburg Address:
“Fourscore and seven years ago our fathers brought forth, on this
continent, a new nation, conceived in liberty, and dedicated to the
proposition that all men are created equal. Now we are engaged in a great
civil war, testing whether that nation, or any nation so conceived, and so
dedicated, can long endure. We are met on a great battle-field of that war.
We have come to dedicate a portion of that field, as a final resting-place
for those who here gave their lives, that that nation might live. It is
altogether fitting and proper that we should do this” …etc
— Gettysburg, PA. November 19, 1863
The “_EOF_” token indicates the end of the here document file.
SENDING SCRIPT OUTPUT AND ERROR MESSAGES TO a LOG FILE
It’s often very useful to have scripts create a log file to let you see what they’re doing and what they’ve done, especially if the script will be run automatically. Well look at some commands from my XBT program and explain how they work to create a log file.
Creating a new log file:
# Generate XBT log file file if not there already:
if [ ! -f /media/$user/XBT_Drive/XBT_Backups/xbt-backup.log ]; then
echo “XBT — External Backup Tool – Log File” \
Creating a new temporary file in /tmp:
date_and_time=”$(date)” # Grabs current date and time and puts in a variable.
echo $’\n’$”Backup sent to XBT_Drive USB from $host by user ‘$user’ on” \
echo “$date_and_time. Any errors?” >> /tmp/backup.log
Using redirection to send only error messages to temporary log file:
(command) 2>> /tmp/backup.log
Using the tee command to append screen output to the temporary log file:
echo “XBT Backup: Successfully completed at $time!” | tee -a /tmp/backup.log
Appending the contents of the temporary log file to the permanent log file:
# Log file is created or appended on XBT_Drive from /tmp:
# (backup.log will be removed from /tmp on next reboot.)
cat /tmp/backup.log >> /media/$user/XBT_Drive/XBT_Backups/xbt-backup.log
Full output for log entry looks like this:
Backup sent to XBT_Drive USB from big-boy by user ‘joe’ on
Fri Jan 11 14:02:58 EST 2019. Any errors?
No errors! 🙂
XBT Backup: Successfully completed at 14:06:41
USING LOOPS IN BASH SCRIPTS
You can setup loops to repeat one task over and over again within a script. A “for loop” is usually the most useful for working with directories full of files or file name arguments at a command line.
This for loop uses the gdebi program to install all the packages in a directory called Packages. This code is phrased in an if statement and is only executed if the directory is found to already exist on the system. It looks like this:
# Install all local .deb packages, if available:
if [ -d “/home/$USER/Downloads/Packages” ]; then
echo “Installing local .deb packages…”
for FILE in ./*.deb
sudo gdebi -n “$FILE”
echo $’\n’$”WARNING! There’s no ~/Downloads/Packages directory.”
echo “Local .deb packages can’t be automatically installed.”
sleep 5 # The script pauses so this message can be read.
This simple for loop grabs file names from the command line arguments and runs a function called “display” on each one and until it’s done:
# Start displaying file(s):
for FILE in “$@”
STOPPING TO ASK FOR USER INPUT WITH THE READ COMMAND
Thus far, we’ve talked about scripts in terms of simple commands that execute automatically. Scripts that act more like programs will usually need to interact with users so they can confirm actions or choose options. This is done with the read command. Read takes input and places it in a variable. Here’s a simple sue of the read command to confirm an action:
echo “Are you sure you want to restore now? [y/N]”
read -n 1 -s choice
The system stops and waits for input from the user. Whatever they type will be entered into the “choice” variable. We can then test for that answer with an if statement to either continue with the program or exit if the user answers with anything other than a lower case ‘y.’ (The capital ‘N’ indicates that it’s the default choice and pressing any key will do the same thing as typing ‘N’.)
if [ “$choice” == “y” ]; then
Commands to complete action.
Commands to skip action or exit the script.
Read can be used to add a pause without asking for specific input:
echo “Press any key to continue.”
read -n 1 -s
Read can catch accidental keyboard input and dump it before moving on to the next command. This is useful when scripts run long processes:
read -t 1 -n 10000 discard
MENU DRIVEN PROGRAMS
BASH scripts that are written to run interactively use greetings and menus to make the script friendly to users. Menus can be constructed using the read command and a series of nested if statements. That works but case statements make wonderful menus. Lets look at the menu for XBT:
XBT — External Backup Tool (Version 3.0)
Main Menu: What would you like to do?
Press the number of your choice:
1 – Backup.
2 – Restore.
3 – Setup XBT Drive.
4 – Get some help.
5 – View backup log. (‘q’ exits.)
6 – Refresh USB Status.
0 – Exit XBT.
Each number corresponds to a script function or a set of simple commands. Here’s the case menu code that makes it work:
read -n 1 -s choice;
case $choice in
6) clear;echo $’\n’$”Refreshing USB Status…”;sleep 2;clear;greeting;;
0) clear;echo $’\n’$”Exiting XBT… Goodbye!”;sleep 2;tput cnorm;exit;;
*) echo “Not a valid choice: Please try again.”;sleep 2;clear;greeting;;
The script does not exit to the prompt. even error messages will dump you back to the greeting menu.
A menu driven program can be run from a terminal with a command or you can create a launcher in your desktop’s menu to start with a click. Terminal programs that are started from the desktop menu will close the terminal when you exit instead of returning to a prompt as they do when launched with a command. The downside of most menu driven scripts is that they can’t be automated or run in a chain with other commands.
I added automated options to XBT after users said they wanted to run it without having to go to the menu to run specific functions.
OTHER TOOLS AND RESOURCES
You can use Git and web sites like GitHub to keep track of versions and share scripts with the world: https://github.com/
My favorite book about BASH is “The Linux Command Line” By William Shotts
You can download it for free: http://linuxcommand.org/tlcl.php
An A-Z Index of the Linux Command Line: https://ss64.com/bash/
LINUX BASH SHELL SCRIPT BASICS Part 2:
STDIN, STDOUT, STDERR AND REDIRECTION
Redirection in Linux is when executing a command you can change the standard input/output devices. The basic workflow of any Linux command is that it takes an input and gives an output.
* The standard input (stdin) device is the keyboard.
* The standard output (stdout) device is the screen.
* The standard error (stderr) is for error messages.
With redirection, the above standard input/output can be changed.
You can use pipes to take the input from one program and send it to another:
ls -l really-big-directory | less
You can send output to files:
ls -l really-gig-directory > ls-output.txt
You can throw output away:
ls -l really-big-directory > /dev/null 2>&1
You can send output to STDERR:
echo “Script Error: This is an error message!” >&2
A variable is a character string to which we assign a value. The value assigned could be a number, text, filename, device, or any other type of data. A variable is nothing more than a pointer to the actual data. The shell enables you to create, assign, and delete variables. You can list shell variables with the env command.
Any input a user adds after a command is placed in special variables called arguments. Each argument is defined by a space between them. If we had a mythical command called twiddle, and we launched it with a command like this:
twiddle file1 file2 file3
What we typed would be put into these shell variables:
$0 = twiddle
$1 = file1
$2 = file2
$3 = file3
If you would type:
$0 = twiddle
$1 = –help
A special shell variable called $@ represents all of the arguments in numerical order. This can be used by a script to loop through several arguments that contain information like file names.
The test command looks for some string of data and returns an error in its exit code if it cannot find it. Using tests is how you can make a clever script that adapts to changes and catches errors.
test -f “.bashrc” && echo “.bashrc is here.” || echo “.bashrc is not here.”
dpkg -l | grep -qw ffmpeg || sudo apt-get install -yyq ffmpeg
You can use the if command to test for files and directories, the exit status of other commands and data you put into variables.
if [ test fir something ]; then
run commands if the answer is yes
run commands if the answer is no
Using if to test for errros:
The exit code of commands that run in bash are placed in a variable called $?. Usually, a 0 means everything went alright, any other number indicates an error.
which ifconfig >/dev/null
if [ “$?” != “0” ]; then
echo “SyncAll Error: The ifconfig utility is not installed!” >&2
echo “Ubuntu and Linux Mint: Run ‘sudo apt install net-tools'” >&2
The exit 1 command will exit the running script with an error code of 1.
ADVANCED SCRIPTING WITH FUNCTIONS
So far, we have been talking about scripts that run one command after another. There is another way to write scripts that makes them more like real computer programs. Functions are sets of commands that get loaded into memory when the script is started and can be called on at any time and in any order as long as the script is running. They are most often used with options entered by the user and/or menus.
A scrips with functions looks like this:
# This is an example script using functions.
# Declare Variables:
local VAR1=1 # Declared as local variable.
Return # Optional command exits a function but not script.
local VAR1=2 # Declared as local variable.
exit 1 # exits script with an error.
# Test for options.
# Coammnds to call functions.
exit # Optional coammnd to exit script with exit staus of 0.
LINUX BASH SHELL SCRIPT BASICS Part 1:
What is BASH?
BASH is a shell that runs in the Linux terminal. BASH is not the only shell that users can choose but it’s the one most commonly shipped with Linux distributions. BASH is also available on Unix, Mac OS and Windows. It is a universal way to interact with a computer. The shell serves as a Command Line Interpreter which means it takes humanly readable commands and passes them to the Linux kernel. The kernel then sends instructions directly to the hardware. BASH doesn’t just run commands and other programs, it has its own programming language too.
What is a BASH shell Script?
BASH does not care where the commands it runs come from. It will happliy accept input from a human being typing on a keyboard, another program running on the system or it can get its instructions from a special kind of text file called a BASH Shell Script. Shell scripts can be used to automate common tasks and they make accomplishing complex computing tasks possible with just one command or the click of a mouse. You can also set shell scripts to run at start up so special parameters can be set or certain programs are opened automatically. They can range from just a line or two all the way up to full-fledged programs.
Yes, You can learn how to write BASH shell scripts!
There are only a few hard and fast rules to shell scripting. Once you learn them, you can feel free to experiment and come up with new ways to do wherever it is you’re trying to do. BASH is very flexible. There are often many ways to do the same thing and you should not let anyone tell you’re doing it “wrong” if your scripts run and do what you need them to. Keep in mind, we all have to start somewhere.
THE BASIC SCRIPT
You will need to use a plain text editor to write your scripts. Every Linux distribution offers one in the menu and there are excellent text editors that run in the terminal. What you use is entirely up to you. A script starts as a plain text file. A basic script looks like this:
The first line is called the “sha-bang” or “hash-bang” and it tells the system that this is a script and that it needs to use the BASH shell to run the following commands. Any line that starts with a # is treated as a comment and will not be considered as executable code by the shell. You can also place a # after a command to add a comment telling what that command is doing.
MAKING A TEXT FILE RUN LIKE A PROGRAM
Once the script is written, it should be saved with a unique filename. You may elect to add .sh as an extension but it is not necessary. I usually only add the .sh to scripts that will not be permanently installed as programs on my machine. The file you saved to must now be made executable before you can test it. You do this with the chmod command in one of two ways:
chmod +x script.sh
chmod 755 script.sh
TESTING THE SCRIPT
Now that the proper permissions are set, the script can be run form a terminal. You will have to use ./ to tell the shel to run it from your working directory, be cause it hasn’t yet been moved to some place in your executable path:
If the script runs as you hopes it would then congratulations, you’ve just written your first script! Sometimes it doesn’t work that easily and you’ll get errors. If you can’t figure out where the errors are coming from, you can activate tracing in your script to get more detailed output telling you just what it’s doing. Open it in an editor and add -x to your sha-bang:
Don’t forget to remove the -x when you’re done fixing the problem.
WHERE TO PUT YOUR SCRIPTS.
You’ll want to move your script to someplace with in your path statement so you can run it like any other installed program on your system. There are two preferred places for scripts you write, programs you compile yourself and any other electable that is not handles by your distribution’s package manager:
Ubuntu and many other Linux distributions will discover that you have created a directory in your home directory called ‘bin’ and add it to the path statement at startup. Executables that you put in ~/bin will be only available to you and you cannot run them with sudo in front of them.
Any executable that you put in /usr/local/bin will be available to all users and can be run with sudo privileges.
If your system is not automatically seeing the newly created ~/bin directory simply open or create a file called .bashrc in your home directory and add these lines to it:
# set PATH so it includes user’s private bin if it exists
test -d “$HOME/bin” && PATH=”$HOME/bin:$PATH”
Restart the system to make this take effect.
Now your script should be ready to run just by typing its name into the command line.
THINGS TO REMEMBER
* BASH is very well documented. Don’t hesitate to search the web for help.
* Always use absolute paths in a script. Ex. /full/path/to/file
* Write detailed comments so you’ll know what you did later on.
* Save a copy of everything you write so you can draw from it later.
Watch the video about P2V!
Just to make it perfectly clear, I am not selling anything.
I do not:
Have a Patreon account,
Have a “Donate” button on my web page,
Have any corporate sponsors,
Sell your private data
Offer anything for download for a fee.
I do not:
Plan on starting a Patreon account,
Plan on adding a “Donate” button,
Seek any corporate sponsorship,
Keep any databases of user data to sell
Ever plan on putting any EzeeLinux content or software behind a paywall.
Asked for a gratuity for giving people one-on-one support,
Accepted unsolicited monetary donations
Accepted hardware donations from those who offered them freely.
Participate in the Google Adsense program and I receive advertising royalty payments from content I provide to YouTube.
EzeeLinux and YouTube are a passionate hobby for me and I do not consider them a job. I cherish and defend my right to say what I want with whatever words I choose and I will defend your right to do the same even If I violently disagree with you. The only thing I ask for is your kind attention and that you show me the same respect I show to you. Thanks to everyone who offers kind words of encouragement and support. It is because of you that I have continued to do what I do.
– Joe Collins