Shell ScriptingLearn CGI scripting using BASH in Linux Shell Scripting

Learn CGI scripting using BASH in Linux Shell Scripting

Web programming has been on a long journey. From the early static HTML files to the very first scripting languages like PHP, Python, Cold Fusion, Java, ASP, to the modern technologies like .net, and Ruby, and finally AJAX-based single page applications like YouTube and Gmail, among others. This is all great. But have you ever thought about using BASH (only BASH) to develop an interactive web page? In this article, you’ll learn more about this.

But isn’t PHP or Ruby a better option than BASH?
Definitely yes. BASH is a scripting language designed for operating-system-related tasks. It was not meant to be used in web programming, and of course it cannot be compared to a fully-fledged web programming language like PHP or Ruby. But learning to make a basic web application with BASH may be useful in the following ways:

  • Learn the details of the HTTP protocol, especially the request and response rules.
  • Bring your BASH knowledge to a new level by experiencing challenges that you may not have seen in basic shell scripting.
  • Perhaps at someday you may have to develop a basic web application on a server where you don’t have access to PHP or Ruby. BASH might save the day for you.

Plus, it’s fun!

What is CGI?
CGI stands for Common Gateway Interface. It is a way to let Apache execute script files and send the output to the client. Those script files can be written in any language understood by the server. Yes, you can write a CGI script using BASH, Korn shell, Perl, Python or even C!

Tools of the trade
In this article we are going to develop an application that will ask the visitor for some information using an HTML form, then display this information on the second page. The following should be available before you start:

  • BASH shell (obviously)
  • A text editor; vi or nano will do the job.
  • Basic knowledge of HTML

Now let’s get started.

The input page (index.sh)
This is the first page of the application. It will contain a simple form where the visitor will enter basic information (name, and e-mail). Then press the submit button, which will transfer him/her to the next page, that will display a greeting message.

If you have a look at the Apache configuration file, typically located in /etc/httpd/conf/httpd.conf on a Red Hat Linux machine, you’ll find that Apache expects to find CGI scripts in /var/www/cgi-bin directory. Those scripts get executed whenever the user visits http://server/cgi-bin. So let’s navigate to this directory and open a new file, call it index.sh and write the following code:

#!/bin/bash
echo "Content-type: text/html"
echo ""
echo "Hello World!"

Save the file, give it execute permissions (chmod +x index.sh), open your browser, and navigate to http://localhost/cgi-bin/index.html. You should see a result similar to the following:
1

Notice the following:

  • The interpreter is identified in the first line (/bin/bash).
  • The content-type is defined in the second line. This is like telling the browser what to expect: is it an HTML document? An image? A binary file? In our case it’s just HTML.
  • An empty line is printed after the content type.

The above three steps are obligatory when writing any CGI scripts. If you miss any of them the server will raise a 500 error code (Internal Server Error).

Now let’s start building our HTML page. A typical one will contain a head, a title, then a body, and some HTML tags to present the content. It might be something like this:

#!/bin/bash
echo "Content-type: text/html"
echo ""
echo "<html>"
echo "<head>"

And so on. But that’s a LOT of echo statements. This costs a lot of typing and is prone to errors. A better method is to use HEREDOCS. Open the index.sh file and change it to be as follows:

#!/bin/bash
echo "Content-type: text/html"
echo ""
cat <<EOT
<!DOCTYPE html>
<html>
<head>
        <title>Welcome to our application</title>
</head>
<body>
        <p>Hello! Please enter your name and e-mail address and press the submit button</p>
        <form action="submit.sh" method="get">
                <label>Name</label>
                <input type="text" name="name">
                <br>
                <label>E-mail</label>
                <input type="text" name="email">
                <br>
                <button type="submit">Submit</button>
        </form>
</body>
</html>
EOT

As you can see, a very simple HTML form that has an entry for the name and another for the e-mail, then a submit button. When the user clicks on this button the form will automatically redirect the browser to the second page: submit.sh with the name and e-mail values appended to the address as query strings. Your page now should look like this:
2

Now let’s code the submit.sh page

Learn the Basics of C Programming Language

The greeting page (submit.sh)
Open a new file in the same directory, call it submit.sh and write the following code inside:

#!/bin/bash
echo "Content-type: text/html"
echo ""
echo "$QUERY_STRING"

Grant the file execute permissions, then on the index.sh, write your name and e-mail address and click submit. You should see the following output:
3

Notice the part of the address after the question mark, these are called Query Strings. This is a method of posting data to the web server. They consist of key value pairs (like name=Ahmed) separated by the ampersand (&). BASH stores this information in a special variable called $QUERY_STRING. In submit.sh file, we just printed the contents of this variable to examine them. But now we want to make use of this text to create a greeting message for the visitor. We can do that using native BASH tools, namely, awk.

Awk is one of the most powerful text processing tools in BASH and UNIX in general. We are going to use awk to split the query string into two parts based on the separator &. Then we’ll use the output to split it once again based on the separator =. In order not to get confused, consider the following example:

In your BASH shell, enter the following:

$ text=name=Ahmed&email=ahmed%40gmail.com
$ echo "$text" | awk '{split($0,array,"&")} END{print array[1]}'
name=Ahmed

We assigned our string to a variable text. Then we fed this string, using echo, to awk, instructing it to split it based on the & character. Awk creates an array placing “name=Ahmed” in place 1 and “email=ahmed%40gmail.com” in place 2. To confirm the value, we instruct awk to print the contents of place 1 in the array, and we have our desired output.

Building upon this, we can feed this output to another similar awk statement, but specifying the & character as a separator as follows:

$ echo "$text" | awk '{split($0,array,"&")} END{print array[1]}' | awk '{split($0,array,"=")} END{print array[2]}'
Ahmed

Ok now we have our method to extract the query string variables in place, let’s use it to create our greeting message. Write the following in sumbit.sh file:

#!/bin/bash
echo "Content-type: text/html"
echo ""
name=`echo "$QUERY_STRING" | awk '{split($0,array,"&")} END{print array[1]}' | awk '{split($0,array,"=")} END{print array[2]}'`
email=`echo "$QUERY_STRING" | awk '{split($0,array,"&")} END{print array[2]}' | awk '{split($0,array,"=")} END{print array[2]}'`
#echo "<h1>Welcome " $name "!</h1>"
#echo "<h2>Your email address is " $email
cat <<EOT
<!DOCTYPE html>
<html>
<head>
        <title>Welcome to our application</title>
</head>
<body>
        <h1>Welcome $name </h1>
        <h2> Your e-mail address is $email <h2>
</body>
</html>

Now go back to the index.sh page, enter the data and click submit button. You should see an output similar to the following:
4

Yeah great! But wait a minute, what are those strange characters doing in the e-mail? Those characters are the URL encoded form of the @ sign. Remember, BASH is giving you the query strings as is, without any treatment. Web languages like PHP take care of decoding/encoding URLs using special functions. But, as mentioned before, BASH was not designed specifically for the web. Accordingly, we have to do the heavy lifting ourselves. Fortunately, the sed command can solve this problem. Now change the fifth line in the submit.sh file, the one where you assign the e-mail variable, to be as follows:

email=`echo "$QUERY_STRING" | awk '{split($0,array,"&amp;")} END{print array[2]}' | awk '{split($0,array,"=")} END{print array[2]}' | sed -e 's/%40/@/g'`

We’re using sed to replace all occurrences of the “%40” string with the @ character. Now if you refresh the page, you should see an output similar to the following:
5

What’s next?
Congratulations, you’ve just built your first CGI web application using only BASH. But as you can see, the application can host a lot of improvements and extra features.

For example, there is no way to make sure the user has entered anything in the input page before clicking the submit button, or may be the e-mail was in an invalid format. Obviously, there should be some form of validation, and friendly error messages shown to the user when something is not correct.

Also, just displaying the user information to the screen is of no use except for demonstration purposes. In a real application, this data should be saved in a backend database, a welcome e-mail should be sent to the user confirming the visit.

Conclusion
In this article, you learned that BASH, although roughly regarded as a shell-scripting language, can be used to make web pages and applications using CGI. You learned how create a simple HTML form, and create a handler page for that form where you can process the entered data and display custom content. You also examined the power of sed and awk to deal with complex text-related problems like parsing query strings.

I hope you enjoyed this article and I hope I was able to show you something new. Thanks for reading.

4 COMMENTS

  1. @Nazeem I think that info would help me too.

    I’m not convinced about the splitting of the QUERY_STRING using awk. The first exa\mple (based on the text above) produces nothing. Not surprising when you realise the output of the first awk is piped to the input of the second:

    $ echo “aaa:bbb” | awk ‘{split($0,array,”:”)} END{print array[1]}’ | awk ‘{split($0,array,”:”)} END{print array[2]}’

    $ echo “aaa:bbb” | awk ‘{split($0,array,”:”)} END{print array[1]}’
    aaa
    $ echo “aaa:bbb” | awk ‘{split($0,array,”:”)} END{print array[2]}’
    bbb

  2. Thanks for nice article!

    That last email line wasn’t working for me, but this worked for me:
    email=`echo “$QUERY_STRING” | awk ‘{split($0,array,”&”)} END{print array[2]}’ | awk ‘{split($0,array,”=”)} END{print array[2]}’ | sed ‘s/%40/@/g’`

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Exclusive content

- Advertisement -

Latest article

21,501FansLike
4,106FollowersFollow
106,000SubscribersSubscribe

More article

- Advertisement -