Showing posts with label Scripts. Show all posts
Showing posts with label Scripts. Show all posts

Thursday, May 14, 2020

Adventures: Coding Standards, Parts 1 and 2

Good news everyone! I have just posted 2 new adventures! In this two-part series we look at bash script coding standards.

In Part 1, we review what a coding standard does and how they work. We next create our own standard called the LinuxCommand Bash Scripting Style Guide.

In Part 2, we look at the new_script program, a bash shell script template generator that makes using our new coding standard fun and easy. Enjoy!

Coding Standards Part 1
Coding Standards Part 2

Tuesday, January 28, 2014

program_list

I've just added another script to the Resources page. This one, called program_list, creates an annotated listing of the executable files (i.e. programs) in a specified directory, or if no directory is specified, /usr/bin.

The listing consists of the program name, a brief description of the program (taken from its man page) and the name of the package that installed the program.  The listing may be produced in 3 different formats: plain text (the default), TSV (tab-separated values), or Markdown.

This script is useful to new users who wish to learn what all the stuff in /usr/bin (or /bin, or /sbin, or /usr/sbin, etc.) does.

Enjoy!

Friday, January 17, 2014

A Couple More Scripts

I have just posted 2 new bash scripts on the Resources page for your edification and enjoyment. They are:

my_cloud - A script to store and manage files on a remote server (a kind of stone-age Dropbox).

photo2mail - A script that re-sizes images. Used to make image files suitable for use as email attachments.

In addition, I have updated new_script to support a more modern coding standard.

Enjoy!

Sunday, October 14, 2012

new_script Version 3

The most popular script on the old version of LinuxCommand.org was new_script, a bash shell script that created bash shell scripts. That is, a script template generator. A few months ago I rewrote new_script to modernize it and make better use of bash features, including arrays. The new version is less than half the length of the previous version and yet it does more.

Using new_script will save you a lot of work by creating a customized template incorporating a parser for your script's command-line options and arguments. The template also includes a number of useful housekeeping routines such as error and signal handlers. The generated script is fully functional (though it does nothing) and is ready for you to insert your program-specific logic.

Synopsis


new_script [-h|--help] [-q|--quiet] [-s|--root] [script]

Description


new_script will, by default, prompt the user for details about the script to be generated:

Enter script output filename >

Choose a name for the generated script file.

Enter purpose of script >

Enter a one-line description of the script.

Include GPL license header [y/n]? >

Entering "y" will insert a GPL license header into the comment block at the beginning of the script.

Does this script require superuser privileges [y/n]? >

Entering "y" will insert a routine that verifies the user has superuser privileges before allowing the script to execute.

Does this script support command-line options [y/n]? >

If you intend to support command-line options for your script, answer "y".

Option 1:
Enter option letter [a-z] (Enter to end) >

If command line options are desired, a series of prompts will appear. First, you will be asked for the short (single letter) form of the option. Enter a letter in the range of a-z to define the option or enter nothing to end the option input loop.

Description of option ------------------->

Enter a short description of the option. This will be used in the "help" message.

Enter long alternate name (optional) ---->

Enter a single-word long option name if desired. For example, if you have an option "h" for a help function, you can specify an alternate long form name for the option such as "help." When your script is executed, you can invoke the help function by including either -h or --help on the command-line.

Note that new_script always includes the "h" and "help" options automatically by default.

Enter option argument (if any) ---------->

If your option requires an argument, enter a single-word descriptor here. For example, if you were creating a script named my_script supporting both an input and an output file, you might have an option for each with their corresponding arguments such as:

my_script -i infile -o outfile

After you finish entering your option information, new_script will generate your custom script template.

Your script will contain a handy error handling routine called error_exit, which is used like this:

error_exit error_message

where error_message is a string containing a descriptive error message. The error_exit function outputs the error_message string to standard error, calls the clean_up function to perform any necessary housekeeping, then exits with an exit status of 1. Here is an example:

error_exit "Something bad happened!"

You can see other examples within the new_script code itself.

Options


The new_script program supports the following command-line options:

-h, --help
Display a help message and exit.

-q, --quiet
Quiet mode. Do not prompt user for script information and output default script to standard output.

-s, --root
Require superuser privileges for execution of generated script.

You may also include the desired file name for the generated script on the command-line after any specified options.

Installation


You can find the script here. To install it, just highlight the text and copy it into a text editor and save the resulting file. If you're feeling clever, you can directly write it to a file via the command-line. Highlight the text as before, open a terminal and enter the following command (assuming you have a bin directory in your home directory, otherwise adjust as needed):

cat > ~/bin/new_script

Paste the script into the terminal by clicking the middle mouse button and type Ctrl-d.

Once you have written the script, give it execute permissions like so:

chmod +x ~/bin/new_script 

Thursday, April 1, 2010

Script: average

A few weeks ago, I was cruising the Ubuntu forums and came across a question from a poster who wanted to find the average of a series of floating-point numbers.  The numbers were extracted from some other command and were output in a column.  He wanted a command line incantation that would take the column of numbers and return the average.  Several people answered this query with clever one-line solutions, however I thought that this problem would be a good task for a script.  Using a script, one could have a solution that was a little more robust and general purpose.  I wrote the following script, presented here with line numbers:


     1    #!/bin/bash
     2    
     3    # average - calculate the average of a series of numbers
     4    
     5    # handle cmd line option
     6    if [[ $1 ]]; then
     7        case $1 in
     8            -s|--scale)    scale=$2 ;;
     9            *)             echo "usage: average [-s scale]" >&2
    10                           exit 1 ;;
    11        esac
    12    fi
    13    
    14    # construct instruction stream for bc
    15    c=0
    16    {    echo "t = 0; scale = 2"
    17        [[ $scale ]] && echo "scale = $scale"
    18        while read value; do
    19    
    20            # only process valid numbers
    21            if [[ $value =~ ^[-+]?[0-9]*\.?[0-9]+$ ]]; then
    22                echo "t += $value"
    23                ((++c))
    24            fi
    25        done
    26    
    27        # make sure we don't divide by zero
    28        ((c)) && echo "t / $c"
    29    } | bc

This script takes a series of numbers from standard input and prints the result.  It is invoked as follows:

average -s scale < file_of_numbers

where scale is an integer containing the desired number of decimal places in the result and file_of_numbers is a file containing the series of number we desire to average.  If scale is not specified, then the default value of 2 is used.

To demonstrate the script, we will calculate the average size of the programs in the /usr/bin directory:

me@linuxbox:~$ stat --format "%s" /usr/bin/* | average
81766.66

The basic idea behind this script is that it uses the bc arbitrary precision calculator program to figure out the average.  We need to use something like bc, because arithmetic expansion in the shell can only handle integer math.

To perform our calculation, we need to construct a series of instructions and pipe them into bc.  This task comprises the bulk of our script.  In order to do something that complicated, we employ a shell feature known as a group command.  Starting with line 16 and ending with line 29 we capture all of the standard output and consolidate it into a single stream.  That is, all of the standard output produced by the commands on lines 16-29 is treated as though it is a single command and piped into bc on line 29.

We'll look at our group command piece by piece.  As you know, an average is calculated by adding up a series of numbers and dividing the sum by the number of entries.  In our case, the number of entries is stored in the variable c and the sum is stored (within bc) in the variable t.  We start our group command (line 16) by passing some initial values to bc.  We set the initial value of the bc variable t to zero and the value of scale to our default value of two (the default scale of bc is zero).

On line 17, we evaluate the scale variable to see if the command line option was used and if so, pass that new value to bc.

Next, we start a while loop that reads entries from our standard input.  Each iteration of the loop causes the next entry in the series to be assigned to the variable value.

Lines 20-24 are interesting.  Here we test to see if the string contained in value is actually a valid floating point number.  To do this, we employ a regular expression that will only match if the number is properly formatted.  The regular expression says, to match, value may start with a plus or minus sign, followed by zero or more numerals, followed by an optional decimal point, and ending with one or more numerals..  If value passes this test, an instruction is inserted into the stream telling bc to add value to t (line 22) and we increment c (line 23), otherwise value is ignored.

After all of the numbers have been read from standard input, it's time to perform the calculation,  First, we test to see that we actually processed some numbers.  If we did not, then c would equal zero and the resulting calculation would cause a "division by zero" error, so we test the value of c and only if it is not equal to zero we insert the final instruction for bc.

This script would make a good starting point for a series of statistical programs.  The most significant design weakness of the script as written is that it fails to check that the value supplied to the scale option is really an integer.  That's an improvement I will leave to my faithful readers...

Further Reading

The following man pages:
  • bc
  • bash (the "Compound Commands" section, covers group commands and the [[]] and (()) compound commands)
The Linux Command Line
  • Chapter 20 (regular expressions)
  • Chapter 28 (if command, [[]] and (()) compound commands and && and || control operators)
  • Chapter 29 (the read command)
  • Chapter 30 (while loops)
  • Chapter 35 (arithmetic expressions and expansion, bc program)
  • Chapter 33 (positional parameters)
  • Chapter 37 (group commands)