Monday, July 26, 2010

5 different ways of doing Arithmetic operations in UNIX

 In this article, we will see the different  options available in performing arithmetic operations in UNIX . These will come handy while working at the command prompt or for writing scripts. For the sake of simplicity,we will take the example of adding two numbers.

1. The first example makes use of the expr command. All the other arithmetic operators(-,/,%) can be used in the same way except for *(multiplication).
$ x=3
$ y=4
$ expr $x + $y
7
  To multiply the numbers, precede the * with a \. This is done in order to prevent the shell from interpreting the * as a wild card.

Monday, July 12, 2010

How to access a child shell env variable in parent shell?

    An environment variable is one which can be accessed in all the child or sub shells of the environment, however a local variable can be accessed in only the shell in which it is defined. We saw this in detail in one of our earlier articles, the difference between an environment variable and a local variable.


   Let's try something to understand this:
$ NUM=20
$ echo $NUM
20
$ ksh
$ echo $NUM

$
  In the above example, NUM is a local variable set to 20. On entering the sub-shell or child shell, NUM is not recognized because it is a local variable in the parent shell.
$ export NUM=20
$ echo $NUM
20
$ ksh
$ echo $NUM
20
$ export VAR=30
$ echo $VAR
30
$ exit   
$ echo $VAR

$
  In the above example, NUM is set as an environment variable using export, and on entering the sub-shell(ksh) we are able to access it. However, the environment variable VAR set in the child shell is not accessible when we went back(exit) to the parent shell.

 In UNIX, any environment variables defined in a shell can only be accessed in the child or sub shells, not in the parent shell. However, there are instances when we would like to access an environment variable in the parent shell which is being set in the child shell.


Let us write a sample scripts to simulate the problem. We are going to write 2 scripts, 'first' and 'second'. The contents of files 'first' and 'second' are as shown below :
$ cat first
#!/usr/bin/ksh
echo "In parent"
second    
echo "The value of MSG is : $MSG"
$ cat second
#!/usr/bin/ksh
echo "In child"
export MSG="ENVIRON"
On running the script 'first', the following happens:
$ first
In parent
In child
The value of MSG is :
  The script 'second' is being called from 'first'. Hence, 'second' is invoked as a sub-shell from 'first'. The variable MSG being set in the 'second' as explained before is not accessible in the parent 'first'.


Solution:
Modifying the scripts 'first' and 'second' as shown below:
$ cat first
#!/usr/bin/ksh
echo "In parent"
second   
. env_file
echo "The value of MSG is : $MSG"
$ cat second
#!/usr/bin/ksh
echo "In child"
export MSG="ENVIRON"
printenv | sed 's/^/export /;s/=/=\"/;s/$/\"/' > env_file
Now, on running the script 'first', the following happens:
$ first
In parent
In child
The value of MSG is : ENVIRON
  So, we made the parent shell 'first' access the child shell 'second' environment variables.

What did we do:

1. In the script 'second', after setting the environment variable, the list of all environment variables(printenv) is copied to a temporary file env_file.

2. The sed command is used to add the word 'export' at the beginning of every environment variable, and to wrap the variable value with double-quotes. This will enable us to simply run the file in the parent shell to export the variables.

3. In the parent 'first', the script 'second' is called. After the call to the 'second', all the environment variables are being sourced using the dot(.) command, and hence all the variables are now available in the parent as well.

4. On printing the variable VAR, got the value being set in the child and hence accessed the child shell environment variable in the parent.


Enjoy with Shells!!!

PS: This article is written with ksh as example. On trying the above say in csh/tcsh, appropriate modifications need to be made to make it work since the syntax of setting environment variables and sourcing a file are different.

Monday, July 5, 2010

How to read database table definition from Unix Shell?

  A UNIX developer or an admin gets to refer to a database table to check for a particular field type, or to check for the columns of a table. Instead of connecting to sqlplus manually every time to get the column names or to connect to toad, we can write a simple shell script which will read or get the table definition. We will see in this article how to create a simple script for this requirement and use it like a command. 

Let us write a script in a file named 'getTable':
#!/usr/bin/ksh

if [ $1 = "-c" ]; then
   cols=1
   table=$2
else
   cols=0
   table=$1
fi

USER="scott"
PASSWD="tiger"
INST="school"

x=`sqlplus -s $USER/$PASSWD@$INST  <<EOF
set heading off
spool result.txt
desc $table
spool off
EOF`

head -1 result.txt | grep -q ERROR

if [ $? -eq 0 ]; then
   echo Invalid table $table
   exit
fi

if [ $cols -eq 1 ]; then
  awk 'NR>2{print $1}' result.txt
else
  awk 'NR>2{printf "%-30s  %-15s\n", $1, !($4)?$2:$4;}' result.txt
fi

\rm result.txt
How to run the script:

1. To get the columns and field type's, say, for a table 'employee', the script 'getTable' can be run as shown below.(In order to know, how to run a script like a command, refer this.)
#getTable employee
EMP_ID         NUMBER(3)
EMP_NAME       VARCHAR2(20)
EMP_DOB        DATE
2. In order to get only the columns of the employee table:
#getTable -c employee
EMP_ID
EMP_NAME
EMP_DOB  
3.  If one is looking for the definition of a particular field, you can do a 'grep' on the output as well.
#getTable employee | grep NAME
EMP_NAME         VARCHAR2(20)

4.  If the table name is invalid, an appropriate error message will be provided:
#getTable employees
Invalid table employees

The script is self explanatory. However, for beginners, the script does the following:

1.  Establishes a connection to sqlplus.
2.  Gets the definition of the table.
3.  If table not defined, errors and quits.
4.  If -c option specified, displays only the column names, else displays the columns along with their field types.
5.  The first 2 lines contain the header information and hence discarded.
6.  Keep in mind, the desc command output contains 3 columns, column name, NOT NULL field and field type.


Happy Shell Scripting!!!


Note: The example taken here is of Oracle database.