2016年5月19日 星期四

[Linux 文章收集] Bash getopts 的使用方法

Source From Here 
Preface 
In an earlier article, we discussed how to pass command line arguments to shell script and ac...em using positional parameters. In this, we will see how to use the getopts command to pass command line options to shell scripts. Command line options are the options or switches passed to a command. For example, -l, -r, -t are some examples of the command line options passed to the ls command. 

Command line options can be classified into 3 types: 
- Options which does not take arguments: 
# ls -l // no arg for -l

- Options which take arguments: 
# cut -d"," file //arg "," for -d

- Options + Additional command line arguments: 
# ls -l file1 file2 file3

The syntax of the getopts command is: 
getopts optstring name

-> optstring - the string which contains the list of options expected in the command line 
-> name - the variable name which is used to read the command line options one by one. 

There are environment variables used in this command: 
* OPTARG : contains the argument value for a particular command line option.
* OPTIND : contains the index of the next command line option.

Let us now discuss with examples how to use the getopts command. 

Examples 

1. Options without arguments: 
Let us create a bash shell script to display the current date and month. This script will take 2 command line options: 
* d - To display date of the current day
* m - To display month of the current month.

- disp.sh 
  1. #!/bin/sh  
  2. while getopts dm name  
  3. do  
  4.     case $name in  
  5.         d)dopt=1;;  
  6.         m)mopt=1;;  
  7.         *)echo "Invalid arg!";;  
  8.     esac  
  9. done  
  10.   
  11. DT=`date '+%d %b'`  
  12. if [[ ! -z $dopt ]]; then  
  13.     echo "Date is: " ${DT/ */}  
  14. fi  
  15.   
  16. if [[ ! -z $mopt ]]; then  
  17.     echo "Month is: " ${DT/* /}  
  18. fi  
  19.   
  20. shift $(($OPTIND - 1))  
Checkout how the getopts is used here.It is used with the while command and an internal switch within while. "getopts dm name" - "dm" are the options expected by the getopts command and "name" is the variable which contains the options. switch case will be present for every option which can be expected and an appropriate action is performed. In our case, on encountering a particular command line option, an approriate flag variable is set. Outside the while loop, depending on the flags, the requisite result is printed. We will discuss the shift command at the end. 

Running the shell script with options: 
# ./disp.sh -d
Date is: 19
# ./disp.sh -d -m
Date is: 19
Month is: 5月

# ./disp.sh -m
Month is: 5月

2. Options with arguments: 
In this example, let us update the same script so that "-d" option can take a value. If "-d" is provided a value n, the date and month displayed will be n days from the current date(GNU Date). For example, if the current date is 30th Aug, and if a value of 2 is provided with "-d", the date and month displayed will be "01" and "Sep". 
- disp2.sh 
  1. #!/bin/sh  
  2. while getopts d:m name  
  3. do  
  4.     case $name in  
  5.         d)dopt=$OPTARG;;  
  6.         m)mopt=1;;  
  7.         *)echo "Invalid arg!";;  
  8.     esac  
  9. done  
  10.   
  11. DT=`date '+%d %b'`  
  12. if [[ ! -z $dopt ]]; then  
  13.     DT=`date '+%d %b' -d "$dopt days"`  
  14.     echo "Date is: " ${DT/ */}  
  15. fi  
  16.   
  17. if [[ ! -z $mopt ]]; then  
  18.     echo "Month is: " ${DT/* /}  
  19. fi  
  20.   
  21. shift $(($OPTIND - 1))  
See the difference!!! "d:m"- a colon after an option indicates the option contains an argument. And the appropriate argument is present in the environment variable OPTARG. One running example as below: 
# ./disp2.sh -d
./disp2.sh: option requires an argument -- d
Invalid arg!

# ./disp2.sh -d 1
Date is: 20
# ./disp2.sh -d 1 -m
Date is: 20
Month is: 5月

# ./disp2.sh -m
Month is: 5月

Similarly, if you want both the options to contain arguments, it should be: "d:m:

3. Options with arguments + Additional command line parameters: 
In this script, the script will be updated to also accept some additional command line arguments. An additional argument will be provided for which a welcome message will be printed. 
- disp3.sh 
  1. #!/bin/sh  
  2. while getopts d:m name  
  3. do  
  4.     echo "OPTIND=$OPTIND ($name=$OPTARG)"  
  5.     case $name in  
  6.         d)dopt=$OPTARG;;  
  7.         m)mopt=1;;  
  8.         *)echo "Invalid arg!";;  
  9.     esac  
  10. done  
  11.   
  12. DT=`date '+%d %b'`  
  13. if [[ ! -z $dopt ]]; then  
  14.     DT=`date '+%d %b' -d "$dopt days"`  
  15.     echo "Date is: " ${DT/ */}  
  16. fi  
  17.   
  18. if [[ ! -z $mopt ]]; then  
  19.     echo "Month is: " ${DT/* /}  
  20. fi  
  21.   
  22. shift $(($OPTIND - 1))  
  23. echo "Welcome, " $1  
One running example: 
# ./disp3.sh -d 2 -m John
OPTIND=3 (d=2)
OPTIND=4 (m=)
Date is: 21
Month is: 5月
Welcome, John

# ./disp3.sh John -d 2 -m
Welcome, John

OPTIND contains the index of the next command line option. Keep in mind, all the command line options provided to the shell script will be present in the variables $1$2 , $3 and so on. How can we now distinguish where the command line options get over and from where the additional arguments start? This is where the OPTIND helps. In this example, when the getopts has processed, OPTIND will contain 4, pointing to the next(4th) argument. And hence, in order to access the command line arguments, it is better if we flush of all the command line options and its arguments prior to the additional arguments. And hence the shift command. 
  1. shift $(($OPTIND -1))  
will become "shift 3" which in other words will shift/flush the first 3 command line options, and hence after the shift "John" will now be $1. It is always a good practice to clean off the command line options at the end of the script. 

Supplement 
Positional parameters in a shell script

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...