my recent reads..

Handling range parameters in Bash

I've come across a few occasions where I wanted to specify a "range parameter" for Bash scripts. Like "1..4" meaning do for 1,2,3 and 4.

Here's a simple trick that uses the (relatively obscure) variable expansion and substring replacement capabilities of the shell.

#!/bin/bash
v_range="1..3" # or you could have taken it as a script parameter
v_start=${v_range%%.*} # chomp everything from the left-most matching "."
v_end=${v_range##*.} # chomp everything up to the right-most matching "."

The repeated %% and ## basically mean you will get a "greedy" match, so you can say "1..4" or "1....5"; it doesn't matter how many repeats you have of the range delimiter. Of course, you can choose other delimiters such as a hyphen, as in "5-10", if you wish.

Now that you have extracted the start and end indices, you can then loop or whatever to your hearts content:
for ((a=v_start; a <= v_end ; a++))
do
echo "Looping with a=$a"
done

For more information on variable expansion, see 9.3 in the Advanced Bash Scripting Guide.

Postscript 5-Feb-2008:
We live and learn! Hat tip to buford for alerting me to the seq utility, which simplifies the iteration over a range, as in:
for a in `seq 1 10`
do
echo "Looping with a=$a"
done

You still need to determine the start and end values of the range, which is the whole point of the variable expansions approach posted here.
read more and comment..

Generating a temp filename in Bash

Here's a function that simplifies the process of generating temporary filenames in shell scripts (I use bash). This function will generate a temporary filename given optional path and filename prefix parameters. If the file happens to already exist (a small chance), it recurses to try a new filename.

It doesn't cleanup temp files or anything fancy like that, but it does have the behaviour that if you never write to the temp file, it is not created. If you don't like that idea, touch the file before returning the name.

This procedure demonstrates the use of variable expansion modifiers to parse the parameters, and the $RANDOM builtin variable.

function gettmpfile()
{
local tmppath=${1:-/tmp}
local tmpfile=$2${2:+-}
tmpfile=$tmppath/$tmpfile$RANDOM$RANDOM.tmp
if [ -e $tmpfile ]
then
# if file already exists, recurse and try again
tmpfile=$(gettmpfile $1 $2)
fi
echo $tmpfile
}

By default (with no parameters specified), this function will return a random filename in the /tmp directory:

[prompt]$ echo $(gettmpfile)
/tmp/324003570.tmp


If you specify a path and filename prefix, these are used to generate the name:
[prompt]$ echo $(gettmpfile /my_tmp_path app-tmpfile)
/my_tmp_path/app-tmpfile-276051579.tmp


read more and comment..

Why we love Tom

I just picked up my copy of Effective Oracle by Design to check some facts. It just took a few moments for it to remind me how much I enjoy and learn from Tom Kyte's work.

Why do we love Tom? I have a theory on this! It comes down to two factors:

  • Substance. In an industry overwhelmed by candyfloss powerpoints, its refreshing to read someone who lives in the details, yet manages to retain sparkling clarity. It's apple pie for the technically oriented: database administrators, developers, and perhaps even a few architects(!).
  • Uncompromising rigour. Never one to let an assumption go unchallenged or untested. If there was an IT version of MythBusters, he would be your Jamie to Dvorak's Adam (or vice versa if you like). Highly opinionated, his opinions are (annoyingly) based on hard facts. Sometimes you just want to jump on the keyboard and hack away to try and prove him wrong ... But that's good! He's got you thinking.

read more and comment..

Indexing with Oracle TDE

Oracle Transparent Data Encryption allows data encryption to be declared in a database schema, meaning that anything persisted on disk is protected from prying eyes.

It is a simple matter to setup TDE by bascially configuring a wallet location in sqlnet.ora, setting the key, and then opening the wallet after database startup. There's a good tutorial for this on OTN.

Declaring data encryption is then simply a matter of using the ENCRYPT keyword in your schema defintion, for example:

CREATE TABLE T1
(SEQ NUMBER(15),
CCNUMBER CHAR(16) ENCRYPT USING 'AES128' NO SALT);
Indexing encrypted columns is covered in the Advanced Security Guide. It mentions specifically that you cannot create an index on a column that has been encrypted with salt (hence the 'NO SALT' above). There is another restriction that you cannot use encrypted columns in functional indexes, but I've yet to find this covered explicitly in the doco. You may be surprised to find out that this also means you get caught if you try to create an index with descending values, such as:

CREATE INDEX T1_AK1 ON T1 (CCNUMBER, SEQ DESC);

This will fail with the error "ORA-28337: the specified index may not be defined on an encrypted column". The reason for this is that the use of "descending" will be treated as a functional index.

Removing the "descending" qualifier allows a valid index to be built:

CREATE INDEX T1_AK2 ON T1 (CCNUMBER, SEQ);


read more and comment..