Thursday, February 5, 2009

Flower brackets {} and variables in UNIX - A perfect match

When passing a variable in unix, the general convention is to use $variable. Although this does suffice in most cases but in some rare cases, it gives connotations totally different than what was originally intended, as shown in the below example.


The requirement
Copy all files ending with ver to ver_old. For example, suppose I have a file called formver, I would like to copy it to formver_old.


The code
below is the code that I wrote to achieve the above requirement.

for i in `ls *ver`
do
cp -p $i $i_old
done


The pitfall
A cursory glance at the code indicates that it should run smoothly like a river. But it doent' and herein lies the catch. Let's have a look at the error and figure out what exactly is wrong with the above code.
__________________________________________________________________

$ for i in `ls *ver`
> do
> cp -p $i $i_old
> done
cp: Insufficient arguments (1)
Usage: cp [-f] [-i] [-p] [-@] f1 f2
cp [-f] [-i] [-p] [-@] f1 ... fn d1
cp -r-R [-H-L-P] [-f] [-i] [-p] [-@] d1 ... dn-1 dn
cp: Insufficient arguments (1)
Usage: cp [-f] [-i] [-p] [-@] f1 f2
cp [-f] [-i] [-p] [-@] f1 ... fn d1
cp -r-R [-H-L-P] [-f] [-i] [-p] [-@] d1 ... dn-1 dn
cp: Insufficient arguments (1)
Usage: cp [-f] [-i] [-p] [-@] f1
cp [-f] [-i] [-p] [-@] f1 ... fn
cp -r-R [-H-L-P] [-f] [-i] [-p] [-@] d1 ... dn-1 dn
cp: Insufficient arguments (1)
Usage: cp [-f] [-i] [-p] [-@] f1
cp [-f] [-i] [-p] [-@] f1 ... fn
cp -r-R [-H-L-P] [-f] [-i] [-p] [-@] d1 ... dn-1 dn
cp: Insufficient arguments (1)
Usage: cp [-f] [-i] [-p] [-@] f1
cp [-f] [-i] [-p] [-@] f1 ... fn
cp -r-R [-H-L-P] [-f] [-i] [-p] [-@] d1 ... dn-1 dn
cp: Insufficient arguments (1)
Usage: cp [-f] [-i] [-p] [-@] f1
cp [-f] [-i] [-p] [-@] f1 ... fn
cp -r-R [-H-L-P] [-f] [-i] [-p] [-@] d1 ... dn-1 dn
__________________________________________________________________

Can you guess or pinpoint as to what exactly is wrong with the above code, which makes it throw this error?

It took me sometime but I finally figured it out. $i_old was being considered as a variable i.e., the shell was reading the variable as $i_old and not as the variable $i appended with an underscore(_) and 'old'.


The solution
The solution to this obviously is to use the flower brackets (braces/parantheses) for the variable $i so as to make it ubiquitous. Now the code looks like:
for i in `ls *ver`
do
cp -p ${i} ${i}_old
done


The conclusion
To conclude, I would like to say to my fellow DBAs who are also into shell scripting, watch out for small things like these, which might make or break your day!

No comments: