Book Image

Linux Shell Scripting Cookbook - Third Edition

By : Clif Flynt, Sarath Lakshman, Shantanu Tushar
Book Image

Linux Shell Scripting Cookbook - Third Edition

By: Clif Flynt, Sarath Lakshman, Shantanu Tushar

Overview of this book

The shell is the most powerful tool your computer provides. Despite having it at their fingertips, many users are unaware of how much the shell can accomplish. Using the shell, you can generate databases and web pages from sets of files, automate monotonous admin tasks such as system backups, monitor your system's health and activity, identify network bottlenecks and system resource hogs, and more. This book will show you how to do all this and much more. This book, now in its third edition, describes the exciting new features in the newest Linux distributions to help you accomplish more than you imagine. It shows how to use simple commands to automate complex tasks, automate web interactions, download videos, set up containers and cloud servers, and even get free SSL certificates. Starting with the basics of the shell, you will learn simple commands and how to apply them to real-world issues. From there, you'll learn text processing, web interactions, network and system monitoring, and system tuning. Software engineers will learn how to examine system applications, how to use modern software management tools such as git and fossil for their own work, and how to submit patches to open-source projects. Finally, you'll learn how to set up Linux Containers and Virtual machines and even run your own Cloud server with a free SSL Certificate from letsencrypt.org.
Table of Contents (14 chapters)

Functions and arguments

Functions and aliases appear similar at a casual glance, but behave slightly differently. The big difference is that function arguments can be used anywhere within the body of the function, while an alias simply appends arguments to the end of the command.

How to do it...

A function is defined with the function command, a function name, open/close parentheses, and a function body enclosed in curly brackets:

  1. A function is defined as follows:
        function fname() 
        { 
            statements; 
        }  

Alternatively, it can be defined as:

        fname() 
        { 
            statements; 
        } 

It can even be defined as follows (for simple functions):

        fname() { statement; }
  1. A function is invoked using its name:
        $ fname ; # executes function
  1. Arguments passed to functions are accessed positionally, $1 is the first argument, $2 is the second, and so on:
        fname arg1 arg2 ; # passing args

The following is the definition of the function fname. In the fname function, we have included various ways of accessing the function arguments.

        fname() 
        { 
           echo $1, $2; #Accessing arg1 and arg2 
           echo "$@"; # Printing all arguments as list at once 
           echo "$*"; # Similar to $@, but arguments taken as single  
           entity 
           return 0; # Return value 
         }

Arguments passed to scripts can be accessed as $0 (the name of the script):

    • $1 is the first argument
    • $2 is the second argument
    • $n is the nth argument
    • "$@" expands as "$1" "$2" "$3" and so on
    • "$*" expands as "$1c$2c$3", where c is the first character of IFS
    • "$@" is used more often than $*, since the former provides all arguments as a single string
  • Compare alias to function
  • Here's an alias to display a subset of files by piping ls output to grep. The argument is attached to the end of the command, so lsg txt is expanded to ls | grep txt:
        $> alias lsg='ls | grep' 
        $> lsg txt 
          file1.txt 
          file2.txt 
          file3.txt 
  • If we wanted to expand that to get the IP address for a device in /sbin/ifconfig, we might try the following:
        $> alias wontWork='/sbin/ifconfig | grep' 
        $> wontWork eth0 
        eth0  Link  encap:Ethernet  HWaddr 00:11::22::33::44:55 
  • The grep command found the eth0 string, not the IP address. If we use a function instead of an alias, we can pass the argument to the ifconfig, instead of appending it to the grep:
        $> function getIP() { /sbin/ifconfig $1 | grep 'inet ';  } 
        $> getIP eth0 
        inet addr:192.168.1.2 Bcast:192.168.255.255 Mask:255.255.0.0

There's more...

Let's explore more tips on Bash functions.

The recursive function

Functions in Bash also support recursion (the function can call itself). For example, F() { echo $1; F hello; sleep 1; }.

Fork bomb

A recursive function is a function that calls itself: recursive functions must have an exit condition, or they will spawn until the system exhausts a resource and crashes.

This function: :(){ :|:& };: spawns processes forever and ends up in a denial-of-service attack.

The & character is postfixed with the function call to bring the subprocess into the background. This dangerous code forks processes forever and is called a fork bomb.

You may find it difficult to interpret the preceding code. Refer to the Wikipedia page h t t p ://e n . w i k i p e d i a . o r g /w i k i /F o r k _ b o m b for more details and interpretation of the fork bomb.
Prevent this attack by restricting the maximum number of processes that can be spawned by defining the nproc value in /etc/security/limits.conf.

This line will limit all users to 100 processes:

 hard nproc 100

Exporting functions
Functions can be exported, just like environment variables, using the export command. Exporting extends the scope of the function to subprocesses:

export -f fname
$> function getIP() { /sbin/ifconfig $1 | grep 'inet '; }
$> echo "getIP eth0" >test.sh
$> sh test.sh
  sh: getIP: No such file or directory
$> export -f getIP
$> sh test.sh
  inet addr: 192.168.1.2 Bcast: 192.168.255.255 Mask:255.255.0.0

Reading the return value (status) of a command

The return value of a command is stored in the $? variable.

cmd;
echo $?;

The return value is called exit status. This value can be used to determine whether a command completed successfully or unsuccessfully. If the command exits successfully, the exit status will be zero, otherwise it will be a nonzero value.

The following script reports the success/failure status of a command:

#!/bin/bash 
#Filename: success_test.sh 
# Evaluate the arguments on the command line - ie success_test.sh 'ls | grep txt' 
eval $@ 
if [ $? -eq 0 ]; 
then 
    echo "$CMD executed successfully" 
else 
    echo "$CMD terminated unsuccessfully" 
fi

Passing arguments to commands

Most applications accept arguments in different formats. Suppose -p and -v are the options available, and -k N is another option that takes a number. Also, the command requires a filename as argument. This application can be executed in multiple ways:

  • $ command -p -v -k 1 file
  • $ command -pv -k 1 file
  • $ command -vpk 1 file
  • $ command file -pvk 1

Within a script, the command-line arguments can be accessed by their position in the command line. The first argument will be $1, the second $2, and so on.
This script will display the first three command line arguments:

echo $1 $2 $3

It's more common to iterate through the command arguments one at a time. The shift command shifts eachh argument one space to the left, to let a script access each argument as $1. The following code displays all the command-line values:

$ cat showArgs.sh
for i in `seq 1 $#`
do
echo $i is $1
shift
done
$ sh showArgs.sh a b c
1 is a
2 is b
3 is c