TweetFollow Us on Twitter

Back to bash Basics: Part 2 Time to Advance Ourselves

Volume Number: 21 (2005)
Issue Number: 11
Column Tag: Programming

Mac In The Shell

Back to bash Basics: Part 2 Time to Advance Ourselves

by Edward Marczak

With any exercise, you need to continually push yourself. Without that extra effort, what once was a challenge becomes easy, something to drift through. At the same time, you may be missing advanced techniques that make other areas easier or more efficient. Similarly, shell scripting can go many layers deep, and you can exercise your knowledge in many ways. Last month in, "Back to bash Basics Part 1," we focused on flow control. You may have noticed some of the things I didn't cover explicitly. There's always more to learn! Let's tie up those loose ends.

More Looping

Since we discussed looping constructs so much last month, that's where we'll pick up. In the select example, you'll see a break statement - that could use some explanation. break simply terminates the current loop. If it were removed from the select example, you would be asked repeatedly which file you want to inspect. Let's see what that would look like:

#!/bin/bash

select theItem; do
        if [ $theItem ]; then
                file $theItem
        fi
done

When this is run, the output looks like this:

Jack-Kerouak:~/bin marczak$ ./st.sh *
1) BidToJob.dmg 
2) bomcheck.sh
3) cl.txt
4) createdmg
5) diskrep.sh
6) exscript
#? 3
cl.txt: ASCII text
#? 4
createdmg: ASCII text
#? 5
diskrep.sh: Bourne-Again shell script text executable
#? ^C

Notice that this time, we need to press ctrl-c to stop the program. break applies to any loop:

#!/bin/bash
for i in $*;
        do
        if [ ! -O $i ]; then
                echo You do not own $i!  I am outta here!
                break
        fi
        echo $i is your file!
done

Running as me, I'm shown:

$ ./bt.sh *
BidToJob.dmg is your file!
bomcheck.sh is your file!
bt.sh is your file!
cl.txt is your file!
[...clipped for brevity]

Running in that same directory as root gives us:

# ./bt.sh *
You do not own BidToJob.dmg! I am outta here!

AOT (or, how the shell will separate files)

Have you ever crossed your AOT (Acronym Overload Threshold)? "There's a problem with the RIP!" Raster Image Processor, or Routing Information Protocol? While there's only so many TLAs (Three Letter Acronyms) that you can deal with, I need you add one more: IFS (no, not Iterative Fractal Systems!). The shell uses the Internal Field Separator to determine how to break apart tokens, and how to separate incoming parameters. By default, IFS is equal to space, tab and newline.

When we discussed the for loop last month, several things were quickly touched upon that can be expanded. In addition to the $@ variable, which expands to individual double-quoted strings, there is the $* variable, which is a single string containing each positional parameter. How do you know where each parameter breaks? $* separates each parameter by using the first character of your IFS variable. We'll get back to how this can be very useful.

Also, last month showed an example that looked something like this:

FILES=`ls *.sh`

for i in $FILES
do
        ...
done

This example 'just works' because ls *.sh will separate its output with linefeeds. Hey, that's one of the characters in IFS by default! What good fortune! This same example will fall apart if you reassign the IFS variable prior to the loop:

IFS="-"
FILES=`ls *.sh`
for i in $FILES; do
...
done

$i will still hold $FILES, but it won't be tokenized - not the way you'd expect (the line feeds will still be in there, but $i won't break on them).

So, then, why would we ever touch IFS? Well, what if you wanted to search through something that is not broken up by a space, newline or tab? Like $PATH, for instance:

#!/bin/bash

IFS=:

for theDir in $PATH
do
        theLatest=`ls -lotr $theDir | tail -1`
        echo Newest file in $theDir:
        echo $theLatest
        echo
done

This simply goes through our $PATH and tells us the newest file in each directory. Could be useful.

Oh, and another thing

Like Apple, shell scripting always seems to have "one more thing." For this month, this thing comes in the form of being able to effectively handle parameters. Time to introduce shift and getopts.

When writing a script, parameters can be accessed a few ways. If you always rely on direct access ($1, $2...etc), you run into some limits. One way to simply loop through all parameters is to use shift. shift makes $1 = $2, $2 = $3...etc. You lose the first value that was assigned to $1. To look for a few specific parameters, you can loop through the values:

#!/bin/bash

while [ `echo $1 | grep "-"` ]; do
        case $1 in
                -a ) echo "You supplied the -a flag";;
                -b ) echo "You supplied the -b flag";;
                -c ) echo "You supplied the -c flag";;
                * ) echo "Usage: $0 -a -b -c";
                exit 1;;
        esac    
        shift
done

Run this code and you'll see:

$ ./shifttest.sh -b -a
You supplied the -b flag
You supplied the -a flag

Now, shift is cool, and still comes in handy, but to truly handle command-line options smoothly, we have to employ getopts. Sure, you can roll your own each time, however, people have come to expect their options to behave in certain ways. One should be able to combine options, as with tar, for example: tar -xzvf blah.tar.gz. Basically, you don't need to roll your own because getopts exists.

getopts allows you to handle options in a standard way. Seeing it in action is the quickest way to get up to speed:

#!/bin/bash

while getopts ":xyz:t" theOption; do
        case $theOption in
                x ) echo "Option x chosen";;
                y ) echo "Option $theOption chosen";;
                z ) echo "Option z chosen with argument: $OPTARG";;
                t ) echo "Option t chosen";;
                \? ) echo "Unknown option chosen"
                        exit 1;;
                * ) echo "You need to supply an option!"
                        exit 2;;
        esac
done

getopts is designed to be dumped in a loop that will feed it arguments passed into the script. It accepts a string that defines the allowed options, followed by a variable that will hold the current option, sans the "-" or "+" (nicely, either are allowed). Using getopts will define two variables: $OPTIND, the current index and $OPTARG, the current argument passed with an option. Running this produces this output:

$ ./gotest.sh -yxz test
Option y chosen
Option x chosen
Option z chosen with argument: test

The string that getopts accepts can only contain letters and the colon character. Each letter is an option you wish to support. If a letter is followed by a colon, that tells getopts that an argument is required. By having a lead colon character in the parameter list string, you suppress the error message that getopts will print if an option is not recognized. In either case, an unrecognized option will set the variable to "?", so you can deal with it.

Put it all Together

I've gotten a request or two asking how to deal with math in the shell. While there are specialized CLI apps that will deal with arithmetic, the shell can do some basic functions, and sometimes, that's all you need. The trick is the underused declare statement. declare tells the shell how you want to treat variables, which are strings by default. So, this doesn't do what one would expect:

$ number1=7
$ number2=8
$ total=number1*number2

When you echo $total, you get "number1*number2": strings. We need to tell the shell that $total should be treated as an integer:

$ declare -i total
$ total=number1*number2
$ echo $total
56

Much better! declare can define several different types of variables:

-a   variable is an array
-i   treat as integer
-r   makes variable read-only
-x   automatic export (like the 'export' built-in)

There are some others, but this is all we need concentrate on for now. All of the usual suspects are available as mathematic operators:

+   Addition
-   Subtraction
*   Multiply
/   Divide
%   Remainder
<<  Bit-shift left
>>  Bit-shift right
&   Bitwise and
|   Bitwise or
~   Bitwise not
!   Bitwise not
^   Xor

In addition to declare-ing a variable to be an integer, you can use let to make the assignment:

let theTotal='5 * 7'

Ah, let....brings me back to my C64 BASIC days...

Now, you should be able to write fairly sophisticated shell script that includes slick input processing, good error handling and even some basic computations!

Make Yourself Useful...

...to everyone. Just remember that bash scripting will help you not only with OS X, but with Linux, IRIX, FreeBSD, and even Windows - if you install a Unix shell there (which can be had for free from Cygwin or Microsoft).

This month highlights the fact that shell scripting is relatively easy, can be fun and powerful. Even better, you'll find bash built-in to every OS X machine you touch! Let this all sink in: while I'll get back to bash scripting in future columns, more Unix detours next month!


Ed Marczak keeps it simple. Tech simplicity at http://www.radiotope.com

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Combo Quest (Games)
Combo Quest 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Combo Quest is an epic, time tap role-playing adventure. In this unique masterpiece, you are a knight on a heroic quest to retrieve... | Read more »
Hero Emblems (Games)
Hero Emblems 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: ** 25% OFF for a limited time to celebrate the release ** ** Note for iPhone 6 user: If it doesn't run fullscreen on your device... | Read more »
Puzzle Blitz (Games)
Puzzle Blitz 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Puzzle Blitz is a frantic puzzle solving race against the clock! Solve as many puzzles as you can, before time runs out! You have... | Read more »
Sky Patrol (Games)
Sky Patrol 1.0.1 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.1 (iTunes) Description: 'Strategic Twist On The Classic Shooter Genre' - Indie Game Mag... | Read more »
The Princess Bride - The Official Game...
The Princess Bride - The Official Game 1.1 Device: iOS Universal Category: Games Price: $3.99, Version: 1.1 (iTunes) Description: An epic game based on the beloved classic movie? Inconceivable! Play the world of The Princess Bride... | Read more »
Frozen Synapse (Games)
Frozen Synapse 1.0 Device: iOS iPhone Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Frozen Synapse is a multi-award-winning tactical game. (Full cross-play with desktop and tablet versions) 9/10 Edge 9/10 Eurogamer... | Read more »
Space Marshals (Games)
Space Marshals 1.0.1 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.1 (iTunes) Description: ### IMPORTANT ### Please note that iPhone 4 is not supported. Space Marshals is a Sci-fi Wild West adventure taking place... | Read more »
Battle Slimes (Games)
Battle Slimes 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: BATTLE SLIMES is a fun local multiplayer game. Control speedy & bouncy slime blobs as you compete with friends and family.... | Read more »
Spectrum - 3D Avenue (Games)
Spectrum - 3D Avenue 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: "Spectrum is a pretty cool take on twitchy/reaction-based gameplay with enough complexity and style to stand out from the... | Read more »
Drop Wizard (Games)
Drop Wizard 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Bring back the joy of arcade games! Drop Wizard is an action arcade game where you play as Teo, a wizard on a quest to save his... | Read more »

Price Scanner via MacPrices.net

Our MacBook Price Trackers will show you the...
Our Apple award-winning MacBook Price Trackers are continually updated with the latest information on prices, bundles, and availability for 16″ and 14″ MacBook Pros along with 13″ and 15″ MacBook... Read more
Amazon is offering a 10% discount on Apple’s...
Don’t pay full price! Amazon has 16-inch M4 Pro MacBook Pros (Silver and Black colors) on sale today for 10% off Apple’s MSRP. Shipping is free. These are the lowest prices currently available for 16... Read more
13-inch M4 MacBook Airs on sale for $150 off...
Amazon has new 13″ M4 MacBook Airs on sale for $150 off MSRP right now, starting at $849. Sale prices apply to most colors and configurations. Be sure to select Amazon as the seller, rather than a... Read more
15-inch M4 MacBook Airs on sale for $150 off...
Amazon has new 15″ M4 MacBook Airs on sale for $150 off Apple’s MSRP, starting at $1049. Be sure to select Amazon as the seller, rather than a third-party: – 15″ M4 MacBook Air (16GB/256GB): $1049, $... Read more
Amazon is offering a $50 discount on Apple’s...
Amazon has Apple’s 11th-generation A16 iPads in stock on sale for $50 (or a little more) off MSRP this week. Shipping is free: – 11″ 11th-generation 128GB WiFi iPads: $299 $50 off MSRP – 11″ 11th-... Read more
Clearance 13-inch M1 MacBook Airs available f...
Walmart has clearance, but new, Apple 13″ M1 MacBook Airs (8GB RAM, 256GB SSD) available online for $649, $360 off original MSRP, in Space Gray, Silver, and Gold colors. These are new MacBooks for... Read more
iPad minis on sale for $100 off Apple’s MSRP...
Amazon is offering $100 discounts (up to 20% off) on Apple’s newest 2024 WiFi iPad minis, each with free shipping. These are the lowest prices available for new minis among the Apple retailers we... Read more
AirPods Max headphones on sale for $479, $70...
Amazon has AirPods Max with USB-C on sale for $479.99 in all colors. Shipping is free. Their price is $70 off Apple’s MSRP, and it’s the lowest price available today for AirPods Max. Keep an eye on... Read more
14-inch M4 Pro/M4 Max MacBook Pros on sale th...
Don’t pay full price! Get a new 14″ MacBook Pro with an M4 Pro or M4 Max CPU for up to $320 off Apple’s MSRP this weekend at these retailers…they are the lowest prices available for these MacBook... Read more
Get a 15-inch M4 MacBook Air for $150 off App...
A couple of Apple retailers are offering $150 discounts on new 15″ M4 MacBook Airs this weekend. Prices at these retailers start at $1049: (1): Amazon has new 15″ M4 MacBook Airs on sale for $150 off... Read more

Jobs Board

All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.