All posts by Andrew Mallett

Adding Color to Your Output From C

Download PDF

Adding Color to Your Programs

Adding Color

Adding color to the output of your programs can make them more visually appealing and adding to their aesthetics. Not only this, though, color will make notices or warning more noticeable to your users resulting in better acceptance. In this blog we will see how to can both add color and start making use of additional functions in C, rather than, using just the main function. So when you are ready and sat comfortably in your chair we shall begin.

ANSI Colors


We have 8 ANSI colors that we can use in our output, this can be doubled to 16 if you take into consideration that these colors can be displayed as standard or in bold for highlighting. To be able to access the colors we need to use and escape sequence followed by the correct color code, the print the text and finally reset the colors.

  • printf(“\033[0;31m”); //Set the text to the color red
  • printf(“Hello\n”); //Display Hello in red
  • printf(“\033[0m”); //Resets the text to default color
  • Escape is: \033
  • Color code is: [0;31m

It is important to reset the color to ensuring that the selected color is terminated and text returns to normal. Using the following table you can view some of the code available.

CODECOLOR
[0;31mRed
[1;31mBold Red
[0;32mGreen
[1;32mBold Green
[0;33mYellow
[01;33mBold Yellow
[0;34mBlue
[1;34mBold Blue
[0;35mMagenta
[1;35mBold Magenta
[0;36mCyan
[1;36mBold Cyan
[0mReset

Simple Hello World in Color

Working with a simple hello world program we can begin to understand how to make use of the color. Firstly we will set the color to be red and bold before moving onto using functions to set the color.

#include <stdio.h>
int main () {
  printf("\033[1;31m");
  printf("Hello world\n");
  printf("\033[0m;")
  return 0;
}

17-09-2016-17-39-39

Adding color to the output was really quite simple; however setting many colors or changing the colors many times will be repetitive. Setting the color often and using more than one color is going to be required where we want to highlight the output with information and warnings.

Using Functions

This is where function can help. It is simple to create functions for red, yellow etc. Let’s take a look.

#include <stdio.h>
void red () {
  printf("\033[1;31m");
}

void yellow {
  printf("\033[1;33m");
}

void reset () {
  printf("\033[0m");
}

int main () {
  red();
  printf("Hello ");
  yellow();
  printf("world\n");
  reset;
  return 0;
}

17-09-2016-17-50-40

We can use the newly created functions as many time as we want and it is as simple as yellow(); reset(); or red(); We, of course, can create more functions to support all colors.

Using the functions the way we have we do not need to return any values. The functions result only in printing the ANSI color codes to the terminal. As we do not return any value then we set the output parameter explicitly to void.

Moving On

It is also likely that we can reuse these function in almost any C program that has text output. In another blog we will see how we can reuse this code by creating and referencing our own header files.

The following video steps you through the process of printing in color.

 

Programming C While Loops on The Raspberry Pi

Download PDF

Writing C While Loops

c while loopsIn the last blog we did use a C while loop to help us iterate though the supplied arguments, as a result we can then check what code we need to run. Using a simpler loop we can see more detail on how they work and where we can use these tools. Using a C while loop we will count down from 10 to 0 and finally print finished to the screen.

Very Simple Code

If we just want to see a while loop up and running then our code can be very quick and we can have the program up and running in little time.

#include <stdio.h>

int main () {

  int c = 10;
  while ( c > -1 ) {
    printf("%d ", c);
    c--;
  }
  printf("\nFinished\n");
  return 0;
}

Looking at the code it is good an does do what we want but the count down is too quick. We test for the counter variable c being greater than -1. Starting at 10 this means that we count from 10 until 0. Using printf we can print the variable and then we decrease the value of the counter c by 1. This is with the line c–;. If we need to count up rather than down we would increment with c++;. Running the code though we do see the numbers appear at the same time.

Slowing Down the Loop

The C while loop that we use happens just a little to frantically for us and we need to allow it to chill a little. The sleep function can help with this and we will find it in the unistd.h. The function sleep(1) will pause for 1 second.

#include <stdio.h>
#include <unistd.h>

int main () {

  int c = 10;
  while ( c > -1 ) {
    printf("%d ", c);
    sleep(1);
    c--;
  }
  printf("\nFinished\n");
  return 0;
}

This now need to be compiled and executed again. We should see the program now waits 10 seconds before displaying anything but still prints all at once. This is because printf will buffer when printing to a console. We need to flush the buffers each time with fflush.

The Working Example

#include <stdio.h>
#include <unistd.h>

int main () {

  int c = 10;
  while ( c > -1 ) {
    printf("%d ", c);
    fflush(stdout);
    sleep(1);
    c--;
  }
  printf("\nFinished\n");
  return 0;
}

Using fflush from the stdio.h we are able to flush the named stream, stdout in this case. Now we print each time and cont down from 10 to 0 more slowly. We now have now seen how to create working C While loops.

Using getopt to Parse Arguments in C

Download PDF

Using getop in C to Read Arguments

Having seen our hello world program in a number of forms so far such as the simple hello and then using if we will now extend this further. Using getopt in the C programming language will allow us to pass options to the program in any order. Thinking for a moment about how we compile the source code we use the option -o to specify the output file. Using either of the following examples would work:

gcc -o hello hello.c
gcc hello.c -o hello

Additionally, we can add in other options, also in any order:

gcc -o hello -Wall hello.c
gcc hello.c -o hello -Wall

using getopt in C programming


Using options in a program is a lot easier than having the pass arguments in the correct order from the command line and we will now see how we achieve this in C using getopt.

Using Loops

Viewing the previous code extract you can see that we make use of a looping structure in C, the while loop. Looping in programming allows us to iterate or go though each item one be one. A simple while loop extract is shown below:

int a = 10;
while (a < 20) {
  printf("The value is: %d\n",a);
  a++;
}

We can see much like the if statement that we looked at within the previous code, the while loop is also a conditional statement. The parenthesis enclose the condition that must evaluate to true. Looping whilst is true we use printf the print the value of the variable a, noting, that the placeholder for an integer is %d. Ensuring the we don’t loop forever the last line of the loop increments the value of the variable, a++. Printing will start at 10 and then continue through to 19.

Using getopt

You may look at the while loop we employ and think it is a little more complicated, alternatively you may see that it does just a little more.  Firstly, be sure to include the header for getopt.

#include <getopt.h>

Each option that we supplied can be in one or more argument to the program and those arguments are still in the array argv. Consider the following command:

gcc -o hello hello.c
  • argv[0] = gcc
  • argv[1] = -o
  • argv[2] = hello
  • argv[3] = hello.c

We need a variable to store the current index value as we iterate through each argument looking for options.

int option_index = 0

The name or identifier that we assign to the variable is our choice.

When using getop an option, such as -o in the gcc program, can take a value.  In the extract of code used in the above screenshot we can provide an argument to the option -u. We need to store that somewhere. For this we setup the user_name array. Both of these variables, option_index and user_name we initialize with a value to prevent warnings from the compiler.

char *user_name = NULL

To assign the true value to the variable option_index we return the index from argv using the function getopt. The first argument is the argument count, acting as the highest number we need at return. Then the array to iterate through, argv followed by the possible options.  Viewing the screenshot we specify the option u and g. The option u takes and argument as it is preceded with the colon, (u:). Our program requires that we state the user name with the option -u.

while (( option_index - getopt(argc, argv, "u:g")) != -1)

The braces enclose the code block for the while loop.

Case Statements

The last element of our new main function is the case statement. The case statement starts with the keyword switch but we subsequently examine the value of the option_index use the keyword case from which it is commonly known.

Using the case statement is a great alternative to adding in many elsif statements.

switch(option_index) {
  case 'u':
    user_name = optarg;
    printf("User is selected\n");
    printf("This user is: %s\n", user_name);
    break;
  case 'g':
    printf("Group is selected\n");
    break;
  default;
    printf("Invalid option\n");
}

Viewing the code extract you can see that we search for both  the option u and g. It is possible that both may be set. Using the option -u we look for the argument and populate the user_name variable with the option supplied. We use the keyword break to close the case for u before searching for the option h.

Whilst this is still a very simple example as we start looking at our own calculations functions this becomes a valuable building block. We will look at next creating a program to convert Centigrade to Fahrenheit but later will add options similar to this so we can covert in either direction based on the option used.

Complete Source Code

#include <stdio.h>
#include <getopt.h>
int main ( int argc, char **argv) {
 int option_index = 0;
 char *user_name = NULL;
 while (( option_index = getopt(argc, argv, "u:g")) != -1){
   switch (option_index) {
     case 'u':
      user_name = optarg;
       printf("User is selected\n");
       printf("The user is %s\n",user_name);
       break;
     case 'g':
       printf("Group is selected\n");
       break;
     default:
      printf("Option incorrect\n");
      return 1;
     } //end block for switch
   }  //end block for while
 return 0;
} // end main block

 

The video follows:

Using Conditional Statements in C

Download PDF

Conditional Statements in C

Conditional Statements in C


Using conditional statements in C, such as the if statement above, we can easily create more flexible code. Having already created the hello.c code before that takes arguments to display information. We now need to investigate how to provide a prompt if the user does not supply arguments. Making the script easy to use with or without arguments and additionally making users happy.

Compiling Code with Warnings

When we compiled our code before using the GNU C compiler or gcc program we did not see any errors. Fabulous, this is what we want but there me problems lurking that we did not know about. Choosing to compile with warning options can tell us of any potential issues that exits. The option -W can enable the warning that we select, additionally, -Wall turns on most if not all warnings and is a good option to use.

gcc -Wall -o hello hello.c

Viewing the output from gcc we now see that two warning are produced and also that these both relate to the return value from the function main . We omitted to define that the function main returns an integer, not only that, we failed to specify any return value. We are C coding criminals! Functions can and often do return values, just think of a function to calculate the area of a rectangle. Taking input arguments, running calculations and as a result returning the answer. We will have both input and output arguments in this case. Any main function is required to return an integer, if we do not specify then it still works but with the return values of functions that run inside main. To control the output ourselves we should add in the required options and as a result, create better code..

Returning Values From Main

int main ( int argc, char **) {
  .....
  return 0;
}

Firstly, looking at the snippet of code we add the word int before the function to specify the data type of the return value. Int is an abbreviation for integer or any whole number. Finally, the last statement in the main function specifies the value to return. We return the value 0. 0 represents success and a value other than 0 represents a failure.

As a result of our coding intervention we can compile the code without any warnings now. Using either using -Wall or the specific warning of -Wreturn-value.

gcc -Wall -o hello hello.c
gcc -Wreturn-value -o hello hello.c

Prompting for User Input

Waiting a while before we move onto the conditional statements in C we will look at how we can prompt for user input. Using a prompt withing the program additionally allows a level of interaction to the program whilst it is running.

char name[100];
printf("Enter your name: ");
scanf("%s", name);

Analyzing the lines we have added to the hello.c file:

  • char name(100);  Firstly we declare a variable name t be of type char. A char is a single character to we set the variable to be an array with indices from 0 to 99 [100]. There is no string data type so we set up and array of characters which is what a string is.
  • scanf(“%s”, name);  Secondly, we have seen printf before and scanf is related to printf but instead of printing data it reads data. We collect keyboard data and store it to the name variable. We set up a string placeholder with %s to accept the data.

Allowing Choice

Having waited all this time this is now where we can add in conditional statements to the C program. We can use the if conditional to look at arguments that have been supplied.

//Program to prompt for user input

#include <stdio.h>
#include <string.h>
int main ( int argc, char **argv) {
  char name[100];
  if ( argc < 2 ) {
    printf("Enter a name: ");
    scanf("%s", name);
  } else {
    strcpy(name, argv[1]);
  }
  printf("Hello %s\n", name);
  return 0;
}

Firstly we see that the if statement looks for the argument count being less than 2, if (argc < 2 ).The number of supplied arguments are maintained in the integer variable argc. When looking to see if the command lines arguments have been supplied we look for < 2 NOT <1. There is always one argument, the program name therefore what we see as the first argument is in fact the 2nd argument. As a result of omitting the argument then we prompt for user input.

Additionally we use the keyword else to maintain the the alternative block of code for what should happen as a result of supplying arguments. Here we use the function strcpy to copy the string from argv[1] to the variable name. Therefore we can print the one variable name no matter if we prompt or pass the value into the program. To access strcpy we include the library string.h.

We can now compile and test the program before we have a C program that makes use of conditional statements. Next blog looks at using getopt to pass options to a program.

Your First C Program on The Raspberry Pi

Download PDF

Writing Your First C Program on The Raspberry Pi

First C ProgramAt theurbanpenguin we offer training and blogs in many languages. Some of these languages are scripted and others compiled.  With a compiled language the source code is transformed into a binary program. When using a scripted language the code is translated at run time by the script interpreter. In general compiled programs should be quicker to run than a scripts when running the same task  In writing your first C program you will learn to use a compiled language. This is where you are creating your own binary or executable programs.


Whilst C is not going to be the easiest of languages to learn it is a great way to start to understand computers and programming. In the Linux community we talk a lot about the value of Open Source programs and when you write you own program you will discover what we mean by Open Source. Many programs in Linux and other Operating systems are written in C making a good choice to learn.

The Learning Environment

We can use Graphical tools and even IDE or Integrated Design Environments to create the code. To keep this tutorial as simple as possible and reducing the need for reliance on additional programs  we will use command line text editors . In this tutorial we will start with nano to get you into the idea of creating the code. In later tutorials I will use vim. I would always recommend vim but if you have not used it before it takes a little getting used to. We want to focus and creating our first C program and not the editor.

Throughout this series of tutorials we will use a Raspberry Pi computer running the Raspbian operating system. It is not a problem using any Linux distribution on the hardware of your choice. It will be sufficient to follow through. Writing in C here is the focus and we do not mind which platform that you choose.

Logging onto the Raspberry Pi we are presented with the GUI desktop or perhaps the command line if we have not enabled the desktop. We are using the desktop but it again does not matter as we will be making use of the command line. Using the desktop allows us to display text in a larger size for the purposes of the video. Using nano as the text editor keeps the editing simple.

Creating the Code

To start we will be creating a directory to organize our code and help us locate files we need. Making sure that we are in our home directory we use the mkdir command to create the structure we need.

cd
mkdir -p src/c

Creating the directory named “src” allows storage of our source code, additionally the sub-directory “c” allows us to organize the source by language. Keeping all files organized makes baking them up easier, and that is not a bad thing.

Moving on with our code-creation we can additionally start our editor and create our first code.

nano hello.c

Using the extension “.c” , as we have here, allows us to easily know the purpose of the file. Entering our new file we can easily start adding code and we often will expect to see comments at the start of the file. Comments lines are for the reader only and are not interpreted by the compiler, additionally, they help our understanding of the code.

Adding Comments

Ensuring we add great comments to our first C program we will take a look at the two styles of comments available.

  • Single line or in-line comments: //
  • Block or multi line comments: /* */

Looking at the first lines of code now we can see the use of both comments types:

//This is an inline comment, commenting the rest of the line
/* This is a block comment that
continues across many lines
until it is closed*/

Adding comments to your code is always appreciated when the code is read by others, additionally you may appreciate it years to come when you revisit the code.

Adding Libraries

The next line that we are adding is a pre-processor command. This tells the compiler to include additional code libraries during the compilation. This libraries will contain pre-written code that we can make use of.

//This is an inline comment, commenting the rest of the line
/* This is a block comment that
continues across many lines
until it is closed*/
#include <stdio.h>

Using diamond brackets around the library name tells the compiler to locate the file, stdio.h in standard system directories rather than adding the full path. The file is actually located in /usr/include/ on the Raspbian OS.

Adding the main Function

Rapidly moving on as fast as out little fingers can type we will create the function main. Each and every C program than can be executed must have a main function. Creating main with the bare minimum we add the following code.

//This is an inline comment, commenting the rest of the line
/* This is a block comment that
continues across many lines
until it is closed*/
#include <stdio.h>
main () {

}

Using parentheses we can group together arguments that may be passed to the function and the braces contain the code. Seeing that the braces are empty we can beginning adding code to the main function.

//This is an inline comment, commenting the rest of the line
/* This is a block comment that
continues across many lines
until it is closed*/
#include <stdio.h>
main () {
  printf("Hello World\n");
}

Noting the code that we have added within the braces we use the printf function. This function is located in the stdlib file that we included earlier, additionally, we can see that pass an argument to printf. The arguments are grouped within the parentheses and we have one quoted string. Using printf we can print to the console screen. We print the text and additionally, the \n represents a new line after the text. There are other special characters that we can print such as \t representing a tab and also we can use \b representing a backspace. Adding a semi-colon to the end of each line tells the compiler that it it the line end.

Congratulating yourself with a big pat on the back this is your first C program, or at least, the source.

Compiling the Program

Having spent hours slaving over the keyboard to create the source code we are ready to compile the code. As a result we will have an executable program. Using Linux we have have gcc, the Gnu C Compiler. Raspbian has this installed by default, while other distributions may need this installing. Using the compiler is easy as we will see in the next code snippet.

gcc -o hello hello.c

Using the option -o tells the compiler the output file to create. Although we have created the binary file now we still have the source code located in the hello.c file. Making the source code available with the binary is creating Open Source Software. As a result you are  contributing to the Linux community.

Executing the Program

Having now created the program we can execute it and see the results of our labors

./hello

Extending the Program

Having created our first C program on the Raspberry Pi we can move onto are next release of the software. Rather than making do with static text we can make the program more dynamic by passing arguments.

//This is an inline comment, commenting the rest of the line
/* This is a block comment that
continues across many lines
until it is closed*/
#include <stdio.h>
main (int argc, char **argv) {
  printf("Program %s is running\n", argv[0]);
  printf("Hello %s\n", argv[1]);
}

Locating the colored test you see the additions that we have made, additionally we detail these for you. Locating the main function you will notice that it now accepts arguments and we define the number of arguments with argc. This is an int or integer datatype. The next argument listed is a character array, argv. This will contain the arguments that we pass though to the program. Adding code to printf we add string place holder with %s. These placeholder are populated in the following arguments. Using argv[0] we print the program name and argv[1] represents the first arguments passed to the program at run time.

  • argv[0] : Index 0 is the first element in the array argv and represents the program name
  • argv[1] : Index 1 is the second element in the array and represent the first argument passed to the program

Running the program with an argument will now effect the displayed message. Don’t forget to compile again.

gcc -o hello hello.c
./hello fred

The video will step you through the process. The next lesson looks at using the IF statement to determine if we have arguments or not. Without arguments we can prompt for user input.

Making use of BASH Script Arguments

Download PDF

Using BASH Script Arguments

BASH Script ArgumentsIn this blog we take a look at how we can use and make use of BASH script Arguments and what this all means to us. We will look at the variable that represents the script $0. As well as all the arguments from $1 through to $9. Where we need double values we can use ${10}. After all we all need at least 10 arguments to our scripts don’t we. Should we need to count the arguments we can us $# and $* represents all arguments. So lets slow down a little and look at what all this means.

The Script Name


All too often we do need to use the variable $0 which represents the full path to the script. I say all too often is that we use this is an error message all of the time. Perhaps in a usage statement when the input is not correct:

if test -z $username && echo "Usage: $0 <username>"

This would print something like: Usage: /usr/bin/listuser.sh <username> . In this way we can see that we must run the script and provide a username.

Script Arguments

We can provide arguments to the script. This are often call positional parameters as the numbers of the variable comes from their numerical position. $1 being the first argument, $2 being the second BASH script argument. Our numbering is straight forward until we need double figures when we need to use the brace brackets {}, to delimit the variable name. So the tenth argument would be ${10}. We can see that providing bash script arguments is not really that difficult:

echo "Argument 1 is $1"
echo "Argument 2 is $2"
echo "Hello $1 $2"

Argument Count

If we need to check the correct number of arguments have been provided before we continue we can make use another of the BASH script arguments. This time $#.

if [ ! $# -eq 1 ]
  then
    echo "You must provide exactly one argument to the script"
    echo "Usage $0 <username>
    exit 1
fi

In this example using BASH script arguments we check for the argument count value using $#. It has to be equal to 1, if it is no then we enter the if block and echo the usage statement before leaving the script.

All Arguments

If we need to cater for all the arguments then we have a variable $* the represents all the arguments as a list.

echo "Hello $*"

So if we run the script as: prompt.sh andrew mallett . The response will be Hello andrew mallett. Note that the script will not correct case. The variable $* is often used with BASH loops to we can iterate through each argument provided to the script.

The following video steps you through the process.


My Book on Shell Scripting is available from good book shops and the publisher Packt.
shellscripting

Working with BASH Variables

Download PDF

Working with BASH Variables


In this blog we take a look at using and working with BASH variables. We should be able to understand how to read variables and set variables by the end. We also should gain some some knowledge of variable scope. So if you are ready let’s go.

What are Variables

BASH variables are named elements that can store values in memory that can be reused later. They can contain number but cannot begin with a number. The value of a variable can be changed unlike constants whose valuse cannot be changed once set.

Environment Variables

Many variables that we use are often described as “Environment Variables” as they go in some way to set up the user environment. Although variable names are case-sensitive and can be in either upper case or lower case; environment variables are usually all in uppercase.

These include

  • $HOME : The path to your home directory, such as /home/pi
  • $PWD : You current working directory
  • $USER : The logged in user name

When we looked at command line lists in the previous blog we could see how we could use some of these variables:

test $HOME == $PWD && echo "You are home"
#This could also be written as
[ $HOME == $PWD ] && echo "You are home"

Here we use the variable HOME and PWD to read or expand the variable we use the $ symbol so HOME becomes $HOME. When in a quoted string such as we use with the echo command we have to use the double-quotes to be able to expand the variable to its stored value. If we just use single quotes then we will not print the variable’s value we will print the dollar and the variable name.  So for example:

echo "$HOME"

Will print /home/pi or wherever your home directory is; whereas:

echo '$HOME'

Will print $HOME

Double quotes allow variables to be expanded whilst single quotes will print the literal string

As well as the variable $PWD which contains the path to the current directory, BASH maintains a variables $OLDPWD which maintain the last directory we were in. There is a shortcut to this using cd –. This will take us to our last directory.

$ cd /usr/share/doc
$ pwd
/usr/share/doc
$ cd $HOME
$ pwd
/home/pi
$ cd -
$ pwd
/usr/share/doc
Using the command cd – we are taken to the previous directory we were in.

Setting Variables

When we set variables ourselves we often use lowercase characters so we do not clash with environment variables. Variables we set are known as user variables.  We can set a variable using a command like this:

user=bob

This will set a variable named user with a value of bob.  We can read this value back by expanding the variable:

echo "$user"

This should print the value bob to the screen.

We can test if a variable has a value ir not by using the command test with the option -z. To start the process again we can use the unset command to clear the variable as it has never been used.

unset user
#clears the variable so it has no value

test -z $user && echo "The variable $user has no value"
#Here we test if the variable has a value or not. If it has no value then we will see the echo text printed to the screen

user=bob
#We give the variable a value

test -z $user && echo "The variable $user has no value"
#As the variable now does have a value we will not see the message printed to the screen

Variable Scope

BASH Variables also have something called scope. By default the scope is local to the shell that the variable was defined in. So its value can only be read from that shell. If you start another shell the variable will not have the value that was set on the parent shell:

unset user
#clears the variable so it has no value

user=bob
#We give the variable a value

test -z $user && echo "The variable $user has no value"
#As the variable now does have a value we will NOT see the message printed to the screen

bash
#We now start a new shell. A sub-shell to the shell in which we set the variable $user

test -z $user $$ echo "The variable $user has no value"
#Now we DO see the message as the variable has no value in the new shell

If we export the variable then it is available to sub-shells. This is normally done with variables defined in a login script to ensure the value is available to all sub-shells:

export user=bob

Where the variable is exported in the way the values is maintained in sub-shells.

unset user
#clears the variable so it has no value

export user=bob
#We give the variable a value and export the variable

test -z $user && echo "The variable $user has no value"
#As the variable now does have a value we will NOT see the message printed to the screen

bash
#We now start a new shell. A sub-shell to the shell in which we set the variable $user

test -z $user $$ echo "The variable $user has no value"
#As the value has been exported we again still see no message as the variable has a value

The video steps you through the process or using and setting BASH Variables.
 

 
My Book on Shell Scripting is available from good book shops and the publisher Packt.

shellscripting

BASH Command Line Lists

Download PDF

Simple Logic with BASH Command Line Lists

bash command line listsWe can simplify our logic and coding by making use of BASH command line lists. This does create simple logic but may effect the readability of your code so use wisely.  As the name suggests bash command line lists are lists of commands that run on the success or failure of other commands. Using the example in the graphic that we have here we first test to see if the script’s first argument is a file; if it is not then we exit with error code 1. We use the || to represent that code should run on left condition returning false . Using && we specify that the code on the right should run only if the code on the left returns true.


If we move through to our home directory using:

cd

Remember cd on its own will take us to our home directory. Now of course we know we are in the home directory but we can see how to test this from within a script.

[ $PWD == $HOME ] && echo "We are home"

First we test to see if the variable $PWD ( your current directory ) is equal to your home directory, if it is we print a message. If we move from this directory and run the code again we will not see the message.

We could also reverse the code:

[ $PWD == $HOME ] || echo "We are not home"

So now we run the echo command only if the first command returns false. So the message will print if we are not in our home directory.

For the example script we use to demonstrate BASH command line lists we see a very sparse scripts:

#!/bin/bash
[ $# -eq 1 ] || exit 1 #ensure we have exactly 1 argument
[ -f $1 ] || exit 2 #ensure that the argument is a regular file
wc -l $1 # count the number of lines in the file argument

We start by testing the number of arguments supplied to the script. We can read the argument count using the variable $#. We check that the count is exactly 1, if it is true we don’t run the command to the right of the test which exits the script.

Next we check that the argument provided is a regular file, if it is not then we run the exit code again. Only after both of these tests have succeeded can we run the 3rd line of code to count the number of lines in the file.

The video follows:

My Book on Shell Scripting is available from good book shops and the publisher Packt.

shellscripting
 

BASH Case Statement

Download PDF

More Conditions using the BASH Case Statement

BASH case statementYes, we can create even more conditions when we make use of the BASH Case Statement in our scripts. Even though we could do the same using many elif condition tests a case statement is easier to read and more efficient. We like easy to read and your computers like more efficient.


If we want to refactor the elif script that we created before we can write it using the fallowing case statement.

case $1 in
     "directory")
        find /etc -maxdepth 1 -type d
     ;;
     "link")
     find /etc -maxdepth 1 -type l
     ;;
     "file")
     find /etc -maxdepth 1 -type f
     ;;
     *)
     echo "Usage: $0 file | directory | link "
     ;;
esac

Some things to note here:

  • We open the code block with case and close it with esac
  • We use the double semi-colon ;; to end each condition action
  • We can use just the closing parenthesis around each test such as “directory”) or we can use the open and close pair as in (“directory”).

Here we are still using a simple example but or course this is something that you can play with and build around your own needs. Like everything the more you start using the code the easier it becomes.

Even though it does work well as a simple demonstration for the bash case statement  I  have always been keen on practical scripts. Scripts that you can use and make use off. So perhaps we can look at a tittle more complex script. This script could perhaps having a script that runs once a week on your servers to check for disk space could be useful. Maybe the script would only email if the percentage of space was at a certain level. We could test for different percentage levels and then run different commands based on those levels.

We first populate the variable called SPACE which will have the space used value from the command df.  Upto 69% we are not worried, then we move up to 89%, then 98% before 99%. Obviously the more space that is in use the more concerned we become.

SPACE=$(df -h | awk '{ print $5 }' | grep -v Use | sort -n | tail -1 | cut -d % -f1 )
case $SPACE in
[1-6]* | ?)
  MESSAGE="All is quiet."
  ;;
[7-8]?)
  MESSAGE="Start thinking about cleaning out some stuff.  There's a partition that is $SPACE % full."
  ;;
9[0-8])
  MESSAGE="Better hurry with that new disk...  One partition is $SPACE % full."
  ;;
99)
  MESSAGE="I'm drowning here!  There's a partition at $SPACE %!"
  ;;
*)
  MESSAGE="I seem to be running with an nonexistent amount of disk SPACE..."
  ;;
esac

You can watch the video here:

My Book on Shell Scripting is available from good book shops and the publisher Packt.

shellscripting

Gather User Input

Download PDF

Gather User Input in Your BASH Shell Script

Gather User InputWelcome to my blog how we can gather user input within our BASH shell scripts. We will be making great use of the built-in command read and your scripts will be awesome. We start with a quick demonstration of an example script. When the script runs we are prompted for the name of the user. We can then check to see if the use already exists before creating the user. Simple but shows read off really well.


As with everything that we can do with a shell script we can also run read direct from the command line to test. So, for example if we want to demonstrate how to gather user input from the command line:

read -p "Enter a user name: "

As we have not specified the variable name to use whatever we enter will populate the variable $REPLY. Should we want to specify out own variable name, which makes better sense especially for longer scripts:

read -p "Enter a user name: " username

Here we will populate a variable of our own choice called username in this example.

The option -p is for the prompt. Other options include

  • -s: To suppress the screen output such as for passwords
  • -n: To limit the number of characters that can be added. For example we might have -n2 where we prompt for a US state.

The script we use in the video is shown below. Note that in the if statement we use the exit command to leave the script if the user already exists:

read -p "Enter a name for the user: " username

if grep -q $username /etc/passwd
then
 echo "The user $username already exists"
 exit 1
fi
 
sudo useradd -m $username

As always we include a video which we hope you will follow.

My Book on Shell Scripting is available from good book shops and the publisher Packt.

shellscripting