Pages

Sunday, November 15, 2009

How to Pass Arguments to Shell Script


Like UNIX commands, shell scripts also accept arguments from the command line.
They can, therefore, run non interactively and be used with redirection and
pipelines.

Positional Parameters:

Arguments are passed from the command line into a shell program using the
positional parameters $1 through to $9. Each parameter corresponds to the
position of the argument on the command line.

The first argument is read by the shell into the parameter $1, The second
argument into $2, and so on. After $9, the arguments must be enclosed in
brackets, for example, ${10}, ${11}, ${12}.Some shells doesn't support this
method. In that case, to refer to parameters with numbers greater than 9, use
the shift command; this shifts the parameter list to the left. $1 is lost,while
$2 becomes $1, $3 becomes $2, and so on. The inaccessible tenth parameter
becomes $9 and can then be referred to.

Example:

#!/bin/bash
# Call this script with at least 3 parameters, for example
# sh scriptname 1 2 3

echo "first parameter is $1"

echo "Second parameter is $2"

echo "Third parameter is $3"

exit 0

Output:
[root@localhost ~]# sh parameters.sh 47 9 34

first parameter is 47

Second parameter is 9

Third parameter is 34

[root@localhost ~]# sh parameters.sh 4 8 3

first parameter is 4

Second parameter is 8

Third parameter is 3


In addition to these positional parameters, there are a few other special
parameters used by shell.Their significance is noted bellow.

$* - It stores the complete set of positional parameters as a single string.
$@ - Same as $*, But there is subtle difference when enclosed in double quotes.
$# - It is set to the number of arguments specified.This lets you design scripts
that check whether the right number of arguments have been entered.
$0 - Refers to the name of the script itself.

Setting Values of Positional Parameters

You can't technically call positional parameters as shell variables because all
variable names start with a letter. For instance you can't assign values to $1,
$2.. etc. $1=100 or $2=venu is simply not done. There is one more way to assign
values to the positional parameters, using the set command.

$ set Helping hands are holier than praying lips

The above command sets the value $1 with “Helping” , $2 with “hands” and so on.
To verify, use echo statement to display their values.

$ echo $1 $2 $3 $4 $5 $6 $7

Helping hands are holier than praying lips

You can simply use $* or $@

$ echo $*

Helping hands are holier than praying lips

$ echo $@

Helping hands are holier than praying lips

Using Shift on Positional Parameters

We have used set command to set upto 9 words. But we can use it for more.

$ set A friend who helps when one is in trouble is a real friend

$ echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11

A friend who helps when one is in trouble A0 A1


Observe that last two words in the output. These occurred in the output because
at a time we can access only 9 positional parameters. When we tried to refer to
$10 it was interpreted by the shell as if you wanted to out put the value of $1
and a 0. Hence we got A0 in the output.
Does that mean the words following the ninth word have been lost? No. If not,
then where have they gone?. They are very much there, safe with the shell But to
reach them we must do the following.

$shift 4

$ echo $1 $2 $3 $4 $5 $6 $7 $8 $9

when one is in trouble is a real friend


Now where have the first seven words gone? They have been shifted out.The first
four words lost for ever, as we did not take the precaution to store them else-
where. What should we have done is:

$ set A friend who helps when one is in trouble is a real friend

$ a=$1

$ b=$2

$ c=$3

$ d=$4

$ shift 4

$ echo $a $b $c $d $1 $2 $3 $4 $5 $6 $7 $8 $9

A friend who helps when one is in trouble is a real friend


Note:In the Korn and bash shells you can refer directly to arguments where
n is greater than 9 using braces. For example, to refer to the 57th positional
parameter, use the notation ${57}.some shells may not support this method.


$ set A friend who helps when one is in trouble is a real friend

$ echo ${12}

real

$ echo ${13}

friend


Bracket notation for positional parameters leads to a fairly simple way of
referencing the last argument passed to a script on the command line.

$ echo ${!#}

friend


$* and $@

Let us look at the subtle difference between $* and $@.

First create three files fileA, fileB, “file temp”
cat > fileA
I LOVE INDIA
Ctrl+d

cat > fileB
HELLO WORLD
Ctrl+d

cat > temp\ file
This file name contains blank space
Ctrl+d

Example:

#!/bin/bash
# Usage: sh arguments.sh fileA fileB temp\ file

echo -e "\033[1mDisplay files content using \$* \033[0m"

cat $*

echo -e "\033[1mDisplay files content using \$@ \033[0m"

cat $@

exit 0

Run the script with file names as arguments.

Output:
[root@localhost ~]# sh arguments.sh fileA fileB temp\ file
Display files content using $*
I LOVE INDIA
HELLO WORLD
cat: temp: No such file or directory
cat: file: No such file or directory
Display files content using $@
I LOVE INDIA
HELLO WORLD
cat: temp: No such file or directory
cat: file: No such file or directory

So there is no difference between cat $* and cat $@.

Modify arguments.sh script as


#!/bin/bash
# Usage: sh arguments.sh fileA fileB temp\ file

echo -e "\033[1mDisplay files content using \"\$*\" \033[0m"

cat "$*"

echo -e "\033[1mDisplay files content using \"\$@\" \033[0m"

cat "$@"

exit 0

Now again run the script with file names as arguments.

Output:
[root@localhost ~]# sh arguments.sh fileA fileB temp\ file
Display files content using "$*"
cat: fileA fileB temp file: No such file or directory
Display files content using "$@"
I LOVE INDIA
HELLO WORLD
This file name contain blank space

Now there is a difference, the two cat commands would become:

cat “fileA fileB temp file”
cat fileA fileB 'temp file'

On execution, the first of these commands would give an error since there does
not exist a file with the name “fileA fileB temp file”. As against this, the
second cat command would display the contents of the files fileA, fileB and
“temp file”. So what you observed ,when not enclosed within "double quotes"
$* and $@ behaves exactly similarly, and when enclosed in "double quotes" there
is a subtle difference.

41 comments:

  1. good job ..........i like ur way to explain

    ReplyDelete
  2. Very well explained!!! Thanks for sharing

    ReplyDelete
  3. what a way to explain, it;s excillent

    ReplyDelete
  4. Thanks, great tut.

    ReplyDelete
  5. very well explained Thanks!!!!!

    ReplyDelete
  6. thank you, it solved my issue.

    ReplyDelete
  7. its very useful and it is nice

    ReplyDelete
  8. Awesome work dude...

    ReplyDelete
  9. nice way of explaining............
    u r good teacher...
    i really liked it....
    regards sayali jadhav...

    ReplyDelete
  10. awesom! cleared my doubts!!

    ReplyDelete
  11. how about some switch related info to a script

    ReplyDelete
  12. I will try to post switch related scripts and info as soon as possible.

    ReplyDelete
  13. Excellent post man , truly useful just to add its worth noting that $* and $@ bash parameters behave identical without double quotes but entirely different if used within double quotes. in case of $* individual parameters will be separated by IFS characters while in case of $@ individual parameters will appear in quotes and separated by space.

    Thanks
    Javin
    10 example of grep command in Unix

    ReplyDelete
  14. Explained very well..Thanks Man

    ReplyDelete
  15. really a good one

    ReplyDelete
  16. Thanks for sharing your knowledge.
    Really very good explanation.

    ReplyDelete
  17. Thank you very much. I got my solution here.

    ReplyDelete
  18. very helpful ..you have done a great job

    ReplyDelete
  19. Amazing way of explaining!!!!!!!

    ReplyDelete
  20. Really Good Explanation -- Vikas Shah

    ReplyDelete
  21. superb!!!!...thanks

    ReplyDelete
  22. Excellent Explanation.. Thanks

    ReplyDelete
  23. way better than my professor, gosh, don't know why I should pay him

    ReplyDelete
  24. thanks. it helps a lot

    ReplyDelete
  25. thanx a lot..
    understood everything very well.
    keep up the good work.

    ReplyDelete
  26. nice post,it really helped me
    regards aamir

    ReplyDelete
  27. Finally! I've been looking for how to set command line args for days! Thank-you!

    ReplyDelete
  28. how to pass parameter to shell script run by scheduled job

    BEGIN
    sys.dbms_scheduler.create_job(
    job_name => '"SYS"."RUN_UPDATE_UCM"',
    job_type => 'EXECUTABLE',
    job_action => '/home/oracle/bkp_script/ucm.sh',
    start_date => systimestamp at time zone 'Asia/Karachi',
    job_class => 'DEFAULT_JOB_CLASS',
    auto_drop => FALSE,
    number_of_arguments => 1,
    enabled => FALSE);
    sys.dbms_scheduler.set_job_argument_value( job_name => '"SYS"."RUN_UPDATE_UCM"', argument_position => 1, argument_value => '/home/oracle/bkp_script/ucm.sh');
    sys.dbms_scheduler.enable('"SYS"."RUN_UPDATE_UCM"');
    END;

    we want to pass date parameter to ucm.sh script as we do in OS

    # ./ucm.sh 20jun2013

    which is run successfully...

    ucm.sh script code is following:

    #!/bin/bash
    export ORACLE_HOME=/u01/app/oracle/middleware/asinst_1/config/reports
    export ORACLE_SID=scm
    $ORACLE_HOME/bin/rwrun.sh report=/home/ERP/SOFTWARES/UCM_SUMMARY_std.RDF userid=scm/palchandarysm@scm desformat=pdf DESTYPE=file DESNAME=/home/ERP/SOFTWARES/PDF/ucm_summary.pdf P_REPORT_DATE=$1

    now we want to run this script from pl/sql and want to pass date parameter as:

    BEGIN
    DBMS_SCHEDULER.run_job('RUN_UPDATE_UCM');
    END;

    ReplyDelete
  29. plz send me reply at this address

    nazar.yousafzai@gmail.com

    ReplyDelete
  30. very thanks.............

    ReplyDelete
  31. Thank U very much

    ReplyDelete
  32. Good morning is good explanation. Some one can helpme? I have a problem, is the next:

    my script is call :

    sh mysScript.sh param1 param2 param3

    par1=$1
    par2=$2
    par3=$3

    sudo mkdir $par1/$par2/$par3

    it cannot create the file because the route is generated like this:
    parameter1 /parameter2 /parameter3

    with a blank space.. what is my wrong?

    ReplyDelete