Monday 28 November 2016

Bash shell arguments


We frequently use arguments with the commands that we type on the command line interface. For example in the command $ls -l /tmp, ls is the command, l is the option & /tmp is the argument. We can use some arguments with our bash shell scripts as well to influence the behavior of the code as per our requirements.


$0
The first shell argument we look at is $0. This represents the name of the file/script which is being run. To illustrate I wrote a small script bargs.sh with the following content:

[root@centops ~]# cat bargs.sh
#!/bin/bash

echo "The name of the script is $0"

When I run the script, the name of the script gets substituted as the value of argument $0.

[root@centops ~]# bargs.sh
The name of the script is /root/bargs.sh
[root@centops ~]# ./bargs.sh
The name of the script is ./bargs.sh


Positional parameters
These arguments are the ones we type after the name of the script separated by spaces. They are $1, $2 & so on. Just a note, in case you are using more than nine arguments with the script then the 10th & subsequent arguments need to be represented by ${10} & so on, In case you write $10, the shell will interpret it as the value of $1 & append a zero to that value while printing.
I've modified the bargs.sh script used earlier to include the arguments $1 & $2.

[root@centops ~]# cat bargs.sh
#!/bin/bash

echo "The name of the script is $0"

echo "The first argument is $1"

echo "The second argument is $2"

I executed the script providing two arguments to it:

[root@centops ~]# ./bargs.sh sahil suri
The name of the script is ./bargs.sh
The first argument is sahil
The second argument is suri


$#
The argument $# represents the number of arguments typed with the script during execution. This is useful for applying a condition where in you want a script to run only when the user enters a required number of arguments. I updated the bargs.sh script as follows:

[root@centops ~]# cat bargs.sh
#!/bin/bash

echo "The name of the script is $0"

echo "The first argument is $1"

echo "The second argument is $2"

echo "you entered $# arguments"

The output from this script is as follows:

[root@centops ~]# ./bargs.sh sahil suri
The name of the script is ./bargs.sh
The first argument is sahil
The second argument is suri
you entered 2 arguments


$* and $@
Both these arguments basically perform the same function, They hold the arguments that were entered with the shell script. But there is a subtle difference in the interpretation. I've expanded the script bargs.sh further to illustrate their usage.

[root@centops ~]# cat bargs.sh
#!/bin/bash

echo "The name of the script is $0"

echo "The first argument is $1"

echo "The second argument is $2"

echo "you entered $# arguments"

echo "The arguments entered are $*"

echo "The arguments entered are $@"

The output of the script is as follows:

[root@centops ~]# ./bargs.sh sahil suri
The name of the script is ./bargs.sh
The first argument is sahil
The second argument is suri
you entered 2 arguments
The arguments entered are sahil suri
The arguments entered are sahil suri

The difference between $* & $@ isn't apparent from the above example. From what I've understood, the arguments $* and $@ will produce the same result unless we change the value of IFS (internal field separator) which is a white space by default. $* counts each argument as an individual string whereas $@ interprets all the arguments as a single string. 
With that understood, lets see an example to demonstrate this.

I've updated our bargs.sh script as follows:

[root@cclient1 ~]# cat bargs.sh
#!/bin/bash

echo -e "\e[34m illustrating bash arguments  \e[0m"

echo "the script name with path is:" $0
echo "the script name is:" `basename $0`
echo "the script location is:" `dirname $0`

echo "the 1st argument is:" $1
echo "the 2nd argument is:" $2

echo "the number of arguments are:" $#

echo "the arguments entered are" $*
echo "the arguments entered are" $@


echo "Changing field separator"
IFS='-'
echo "the arguments using \$*" "$*"
echo "the arguments using \$@" "$@"


The output from this script is:

[root@cclient1 ~]# ./bargs.sh sahil suri
        illustrating bash arguments
the script name with path is: ./bargs.sh
the script name is: bargs.sh
the script location is: .
the 1st argument is: sahil
the 2nd argument is: suri
the number of arguments are: 2
the arguments entered are sahil suri
the arguments entered are sahil suri
Changing field separator
the arguments using $* sahil-suri
the arguments using $@ sahil suri

In the above example I changed the value of IFS from the default white space to -. So $* interpreted sahil & suri as separate arguments & placed a - as separator between them but $@ did not.


$?
This isn't an argument supplied to a shell script. But I felt the need to mention this anyway in this article. The $? variable stores the exit status of the immediately executed command.An exit status of zero indicates successful execution of the program whereas a non-zero exit status indicates an unsuccessful execution. For example

[root@centops ~]# ls /
bin  boot  cgroup  check_dir  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  Packages  proc  quadstor  R_D  root  sbin  selinux  srv  sys  tmp  usr  var
[root@centops ~]# echo $?
0
[root@centops ~]# ls /sahil
ls: cannot access /sahil: No such file or directory
[root@centops ~]# echo $?
2

This variable is critical to scripting because using it's value we can shape the flow of the script.

No comments:

Post a Comment

Using capture groups in grep in Linux

Introduction Let me start by saying that this article isn't about capture groups in grep per se. What we are going to do here with gr...