Please enable JavaScript eh!

 ⌘ Web Mechanic ⌘ 

Bash Scripting


Functions 102

We talked about functions previously, so we have an idea what they are and why we would use them. But in my experience, knowing about something is not the same as seeing how it is used, then using it.

So I've found or invented a few bash functions that show how easy it is to make something useful. Some bash operations are a bit complex, and you have to keep looking up how to do that job. These functions should ease that. After all, that's a large part of what programming is, right?

Another note about these functions: there will be piping and some new commands (awk, sed, grep, wc).

Most of these have to do with string manipulation simply because that is what I deal with a lot, and I'm making an assumption you have a similar experience.


Create a library of bash functions:

  • Save your functions in a separate file
  • Include it in your main script using the source command
  • Consider creating separate libraries for different purposes
  • Here is what's coming up:

    Many of these functions are coded to use a string passed to them as a positional parameter ($1, $2, etc.), with the result returned.

    But the result can be saved as a variable if needed.

    You are encouraged to TYPE these code examples by hand, NOT pasting.
    This will give you more confidence as you make mistakes and learn.

    ltrim

    ltrim() {
        echo "${1#"${1%%[![:space:]]*}"}"
    }
    

    Note the use of [:space:] in there. That is a special character class of regular expressions. It represents spaces and tabs in text.

    The bang (!) ahead of that means to ignore or negate whatever follows.

    Usage:
    myText="     There are 5 leading spaces in this string"
    ltrim "$myText"
    There are 5 leading spaces in this string

    Because of the way HTML and web pages handle spaces, you may experience some odd effects with this one.

    In HTML, browsers typically throw multiple contiguous spaces away - to actually display them you have to use the code   (non-breaking space).

    If you are scripting for Terminal use, or dealing with a straight ASCII output, you should not have any problems.


    rtrim

    Obviously if you have an ltrim, you have to have an rtrim,right?

    rtrim() {
        echo "${1%"${1##*[![:space:]]}"}"
    }
    

    Again using [:space:] to represent spaces or tags.

    Usage:
    MyText="The slow lazy dog slept until noon!     "
    echo "-->$MyText<--"
    echo "Length: ${#MyText}"
    MyTextR=$(rtrim "$MyText")
    echo "Trimmed: ${#MyTextR}"
    
    -->The slow lazy dog slept until noon!&nsbp;&nsbp;&nsbp;&nsbp;&nsbp;<--
     Length: 40
    Trimmed: 35

    rot13

    OK, I lied. DON'T throw this one out. It's actually quite old (I remember it from the 1980's).

    rot13 is a way of making sensible text appear non-sensible (encipher). This is NOT encryption, but was used for years so a message or some text is not immediately readable (obfuscate).

    It works by replacing each letter with the letter 13 places away in the alphabet.

    The rot stands for rotation and 13 means how many places away the replacement letter is.

    In it's day it was so popular there were applications that would encode or decode text encoded this way. Everyone used it.

    More about rot13 here.

    This is a simple function using the tr command in a pipe.

    rot13() {
        echo "$1" | tr 'A-Za-z' 'N-ZA-Mn-za-m'
    }
    

    So to see how it works ...

    myText="The slow lazy dog slept until noon."
    rot13 "$myText"
    
    Gur fybj ynml qbt fyrcg hagvy abba.
    

    Say what?

    Of course to read what it actually says, you have to do the same operation on that string:

    myText="Gur fybj ynml qbt fyrcg hagvy abba."
    rot13 "$myText"
    
    The slow lazy dog slept until noon.
    


    rev-chars

    Reversing text in a string may mean reversing characters, or words. This one does characters.

    reverse() {
        local str="$1"
        local reversed=""
        local len=${#str}
        for ((i=$len-1; i>=0; i--))
        do
            reversed="$reversed${str:$i:1}"
        done
        echo "$reversed"
    }
    
    Usage:
    MyText="Hello World"
    echo " \$MyText: $MyText"
    MyTextR=$(reverse "$MyText")
    echo "\$MyTextR: $MyTextR"

     $MyText: Hello World
    $MyTextR: dlroW olleH

    To reverse words in a string, see Strings.


    rep

    I use this feature sometimes when I want to print the same character or string several times, like this:

    ========================= All Done =========================
    rep() {
        local str="$1"
        local count="$2"
        for ((i=1; i<=$count; i++))
        do
            echo -n "$str" # do not print a newline character
        done
    }
    rep "=" "25"
    echo -n " All Done "
    rep "=" "25"
    

    Defining the variables str and count as local means they are only accessible in this function. So other variables named the same will not be affected.


    swap

    Another frequent task you might be getting tired of doing - replace some text with some text.

    You have a document with "978-1-003-00641-1" in it several times, but you notice it should be "978-1-003-00641-7". Yes your text editor can do this for you, but we're doing bash here, so ...

    swap "isbn.txt" "978-1-003-00641-1" "978-1-003-00641-7" "isbn-fix.txt"
    

    In this one we use sed (stream editor) to do the magic...

    swap() {
    	local input="$1"
    	local original="$2"
    	local replaced="$3"
    	local output="$4"
    	cat "$input" | sed "s/$original/$replaced/g" > "$output"
    	cat $4
    }
    

    Using local again to define our variables to only affect the function.

    Then use cat to read the whole file and pipe it to sed.

    sed is pretty cool and we will talk more about it. For now we use the s option to do substitution.

    We put the 2 strings we want to swap bookended by the front-slashes /.

    Then we add a flag g to indicate we want to swap ALL the occurrences (globally) in the input string.

    Finally we give a name to the file we want the fixed output to be put into.

    BEWARE
    This redirection will OVERWRITE any existing file of the same name
    sed does NOT write any changes to a file unless you tell it to.

    sed is a stream-oriented non-interactive editor. It is designed in a typical Unix fashion, taking input from one command and either sending it to the standard output or piping it to another command.

    See sed for the man page.

    You would be wise to get to know this one well.

    Functions 103