Programming with BASH

Discussion in 'Advanced Tutorials' started by LinuxDotOrg, Jul 10, 2013.

  1. LinuxDotOrg

    LinuxDotOrg Administrator

    Messages:
    34
    Likes Received:
    72
    Trophy Points:
    8
    Programming with BASH

    Thought it might sound like it, BASH isn't one of those captions that pop up (along with Ooff! and Biff!) when Batman and Robin are fighting the bad guys on the old 60's TV show. BASH actually stands for Bourne Again Shell. The reason for the name goes back to Steve Bourne who wrote the original Bourne Shell for Unix. When the GNU created a Free Software equivalent, they named it after Steve's shell and added a little pun on his last name.

    If you're a system administrator, making BASH scripts is going to be one of those mandatory things. But far from being a chore, you'll learn that it's going to make your work and your life a whole lot easier.

    Our First BASH Script

    The first thing that a BASH script needs is the proverbial 'shebang'. These are two characters:

    Code:
    #!
    Following this, you should include the path to the BASH interpreter. So the first line of your script should look like this:

    Code:
    #!/bin/bash
    If your default shell is BASH, the line:

    Code:
    #!/bin/sh
    does the same thing. It's just a symbolic link to /bin/bash. But if your default shell isn't BASH, you won't be invoking /bin/bash if your write a shell script with that first line. Since on Linux systems, BASH is normally the default shell, you'll see most BASH scripts start with

    Code:
    #!/bin/sh
    From there on, you're free to do what the shell allows. Shell scripts created for administration purposes (which are the majority of scripts) are made up of lines that invoke other commands. Let's look at a simple example. Let's say you have email users on your system but you don't have a quota in place. Still, you want to monitor the sizes of the mailboxes to make sure that people aren't taking up more space than they should. This script, run from crontab, would do the trick nicely:

    Except for the shebang, comment lines start with #


    Code:
    #!/bin/sh
     
    # show us the size of email spools email spools
    # date in YYYY-MM-DD format
    today=`date +%Y-%m-%0e`;
    # subject and recipient variables
    subject="Mailcheck";
    sendto="admin@linux.ork";
    cd /var/spool/mail
    ls -lSh | awk '{print $5, $9}' | grep "(G|M)" | mail -s $subject-$today $sendto
    # end script

    First off, you'll see that we've declared some variables. These variables are not prefixed by any characters when declared but they are prefixed by the dollar sign ($) when used. You've also noticed that variables can be other commands, as in this example with the date command. When you use a command as a variable, it must be put inside backticks (` `).

    First, the script changes to the directory where the mail spools are located. The the scripts performs an 'ls' with options and presents a list where the biggest spools are displayed first with their size in human readable format. This is piped to awk, which sorts out the size and the user name. The awk output is grepped for those spools which are in the Megabytes and Gigabytes. This is then piped to the 'mail' command and sent to the admin account with the subject plus the date we declared in those variables. The admin will then have a nice sorted list of who is using the most space in /var/spool/mail.

    Built in Variables

    Though we created our own variables in the previous example, BASH also comes with what are known as built invariables. Here is an example of a script with frequently used built in variables.


    Code:
    #!/bin/sh
     
    echo "You are user $UID on $HOSTNAME"
    echo "Your home directory is: $HOME"
    echo "$HOSTNAME is running $OSTYPE"

    The output of this script should yield something similar to this:



    As you can see, we didn't have to previously declare any of these. That's why they're known as built-in variables. Their use will save you a lot of time in writing your scripts. You can find a complete list of built-in variables in theGNU BASH Reference Manual

    Interactive Scripts

    Though we mentioned that the main use of BASH scripts is for automating administrative tasks, there may be times when you need users to interact with scripts. If you want a user to input information, you need to use the variableread. Let's take a look at the following example:


    Code:
    #!/bin/sh
     
    echo -n "Enter the name of a city: "
    read CITY
    echo -n "$CITY is "
    case $CITY in
    London | Paris | Berlin | Rome) echo -n "in Europe";;
    'New York' | Chicago | Washington) echo -n "in The USA";;
    Tokyo | Bejing | Bangalore) echo -n "in Asia";;
    *) echo -n "some place - but I don't know where";;
    esac

    As you can see, we've declared a variable that's going to depend on what the user types in when he/she is prompted for the name of a city. After, we have several options for each case. If the user types in the name of a city we've contemplated here, he/she will be given a message as to where the city is. If not, the script will display a message that it doesn't know where the city is. Any answer is represented by the asterisk (*)

    Making Sure You Have What You Need

    If you have to manipulate the contents of a file, it's a good idea to check if this file exists first. Here is a simple BASH routine to do this using the if command:


    Code:
    #!/bin/sh
     
    if test -f /var/log/mail.log; then
    printf "The file existsn";
    fi

    This is a good idea, as it would render your script useless if you had it set to manipulate a file that didn't exist.

    If Loops: A Practical Example

    I was a full-time English as a foreign language teacher for 12 years, so I can't resist giving you this example of a multiple-choice test using a BASH script.


    Code:
    #!/bin/sh
     
    PS3="Choose the number of the correct word to fill in the blank: "
    echo "The emergency brake let go and car rolled ______ the hill"
    select SENT1 in up down along beside
    do
    if [ "$SENT1" == "" ]; then
    echo -e "You need to enter somethingn"
    continue
    elif [ "$SENT1" != down ]; then
    echo -e "Sorry. Incorrectn"
    echo "1. Incorrect" >> eoiexam.dat
    elif [ "$SENT1" == down ]; then
    echo -e "Great!n"
    echo "No. 1 - Correct" >> eoiexam.dat
    break
    fi
    done

    The script makes use of the 'elif' routine to sort out answers that aren't correct. You will also notice that it writes the results, whether correct or not, to a file.

    If you're in the teaching profession, you could expand on this to give your students a quick quiz.
  2. Piet

    Piet New Member

    Messages:
    3
    Likes Received:
    1
    Trophy Points:
    3
    hey,
    really nice tutorial.
    Would you continue this tutorial with more difficult ways or scripts?
    Virneto likes this.
  3. Virneto

    Virneto Member

    Messages:
    46
    Likes Received:
    21
    Trophy Points:
    8
    Yeah, good suggestion. Count me in! ;)
  4. ryanvade

    ryanvade Administrator Staff Member Staff Writer

    Messages:
    1,389
    Likes Received:
    454
    Trophy Points:
    83
    BASH is awesome!!!
    I have talked about BASH a lot:
    BASH Script
    Virneto likes this.
  5. kanika

    kanika New Member

    Messages:
    2
    Likes Received:
    1
    Trophy Points:
    1
    how i make my own game like gta deluxe....o_Oo_Oo_Oo_Oo_Oo_Oo_Oo_O
  6. JDG

    JDG New Member

    Messages:
    17
    Likes Received:
    2
    Trophy Points:
    3
    I thought BASH was /bin/bash? Isn't /bin/sh the Bourne Shell?
  7. ryanvade

    ryanvade Administrator Staff Member Staff Writer

    Messages:
    1,389
    Likes Received:
    454
    Trophy Points:
    83
    bash and sh are two different shells. Basically bash is sh, with more features and better syntax. Most commands work the same, but they are different.

    Having said that, you should realize /bin/sh on most systems will be a symbolic link and will not invoke sh. In Ubuntu /bin/sh used to link to bash, typical behavior on Linux distributions, but now has changed to linking to another shell called dash. I would use bash, as that is pretty much the standard (or at least most common, from my experience). In fact, problems arise when a bash script will use #!/bin/sh because the script-maker assumes the link is to bash when it doesn't have to be.

    For more info, http://man.cx/sh, http://man.cx/bash.

    Source: http://askubuntu.com/questions/141928/what-is-difference-between-bin-sh-and-bin-bash
    Mitt Green and JDG like this.
  8. Maverick1

    Maverick1 New Member

    Messages:
    27
    Likes Received:
    5
    Trophy Points:
    3
  9. loomsen

    loomsen New Member

    Messages:
    1
    Likes Received:
    0
    Trophy Points:
    1
    Hi folks,

    I don't wanna be the party pooper, but I find this post a little misleading. First of all, it should definitely be in the beginner section, due to some obvious newbish mistakes in the scripts and snippets shown above.

    Just from a quick glance:
    1.) Don't use backticks, use $()
    2.) Don't cd in a script (you never cd in a script, if, and you double check that condition, you need to, use pushd and popd)
    3.) Don't parse ls!
    4.) No! Don't parse ls!
    5.) you clearly never pipe grep to awk or awk to grep, it's absolutely pointless. Use awk's built in regular expression matching, save a call to grep.
    6.) Use lowercase variables (to avoid accidential overriding of environmental variables)
    7.) An if-statement is not a loop!
    8.) Always quote your variables (unless you have a very good reason not to - which means you have to be aware of how bash's parameter expansion works. If you're not, ALWAYS quote your variables.)

    Really, there are so many mistakes, this tutorial doesn't actually help in educating people... A link to http://mywiki.wooledge.org/BashGuide would have been more useful.

    I'm sorry for this harsh first comment.
  10. Videodrome

    Videodrome Active Member

    Messages:
    221
    Likes Received:
    85
    Trophy Points:
    28
    I'm not a big time programmer, but I love to copy paste code from tutorials and run everything as a script.

    :cool:
  11. Ashutosh Kumar

    Ashutosh Kumar New Member

    Messages:
    1
    Likes Received:
    0
    Trophy Points:
    1
    Hi friends,
    Currently working on a scenario that i need to connect from one environment(IP add1) to another environment(IP add2) on BASH shell,using the concept of private/public key generation from ssh keygen
    .And i have already created Private/public key for first environment.
    But while getting inside the .ssh/ directory found the there is alreadt authorize_key file with some content of other remote environment.But i want the my environment with IP add1 should also be able to connect to IP add2 env.So for this what i need to do?Do i need to make another authorization file in second env ie IPadd2.
  12. Eric Z. Ma

    Eric Z. Ma New Member

    Messages:
    10
    Likes Received:
    9
    Trophy Points:
    3
    No space around '=' when you assign a value to a variable. This is different from most modern programming languages.
    JDG likes this.
  13. MikeyD

    MikeyD Active Member

    Messages:
    232
    Likes Received:
    113
    Trophy Points:
    43
    I wouldn't agree with never using backquotes, $() is likely more readable, but both are completely accurate and have their uses, and backticks are more compatible with older shells.

    A lot of our older servers at work (AIX, Solaris SPARC, etc.) will use csh by default (hate csh!!) or legacy versions of sh, or have sh symlinked to another shell like tsh/ksh many of which don't interpret $() so I generally use backticks unless I'm nesting commands within commands and its getting confusing and I know the script will only be used on a system with a bash or similar shell.

    I'll agree $() is more forward-compatible, but it really depends on the systems your script will be running.
  14. JDG

    JDG New Member

    Messages:
    17
    Likes Received:
    2
    Trophy Points:
    3
    First of all let me say that I do understand the differences between BASH and the Bourne Shell very well and am aware of the symbolic linking as I have been administering Linux for quite some time.

    Also, thank you for the references and your insight. I am in definite agreement with you, but I want to ensure you and I are on the same page.

    Consider my thoughts on the matter:

    The reason I posed my question was not so much to get into a discussion about which Linux distribution uses what shells but more so to call attention to the differences between the shells and that symbolic linking does sometimes exist. I'll elaborate on the symlinking below.

    Additionally, Linux has been around for quite some time and from an functional point of view these shells are not the same as you so eloquently described. One cannot tell from a script whether or not a symlink is present. After all one could play a mean joke and symlink your shell to just about anything right? I still maintain older systems that have only Bourne installed either because that's how the system was released or it was made this way because of an administrators desire to minimize an installation to only the core components.

    I've also been fortunate enough to have an opportunity to mentor folks on Linux administration and I try to stay as true to the foundation as I can. I believe foundational knowledge is very important because cutting-edge distributions are constantly changing and there are still many who use the less 'fancy' Linux distros because they serve some special purpose.

    Thank you again for your insight and hopefully you see some good points being raised in my response. We don't necessarily have to agree on every point, but I want to ensure that there is not some later confusion or complaint when scripts do not work or systems do not process as instructed.
  15. JDG

    JDG New Member

    Messages:
    17
    Likes Received:
    2
    Trophy Points:
    3
    I am like you in many ways :). I like to keep a 'cookbook' if you will. I am a little wary of copying and pasting some things I find though. It might be my paranoia *joking* or the malware analysis work I do, but that's a story for another day.
  16. MikeyD

    MikeyD Active Member

    Messages:
    232
    Likes Received:
    113
    Trophy Points:
    43
    I think the OP did a fairly good job of explaining that though...

    JDG likes this.
  17. ryanc

    ryanc New Member

    Messages:
    12
    Likes Received:
    7
    Trophy Points:
    3
    I find it interesting that you didn't mention the need to set the execute permission on the script before running it. Or that to execute it (for most people) you will need to include the path (relative or absolute) to the script?

    Bash Scripting Tutorial
  18. ZHANG/ZHIKUN

    ZHANG/ZHIKUN New Member

    Messages:
    26
    Likes Received:
    2
    Trophy Points:
    3
    good explanation.
  19. Maverick1

    Maverick1 New Member

    Messages:
    27
    Likes Received:
    5
    Trophy Points:
    3

Share This Page