Perl like GetOpt functionality for Shell Scripting

One of the powerful features of the terminal app which’s available by default on Linux & Mac OS is the unix shells it supports. It offers plethora of unix commands which can be bunched together in a file (called ‘the script’) to run as a group. You would use the script for example in-order to accomplish a task automatically and obviously this is one of the key features which everyone admires. Ever wondered how to output a professional looking help when someone runs your script? Something that’s available & supported in most of the GNU unix commands like sed?

Output of “sed –help” on a terminal
A good script would handle the arguments & options provided to it in an efficient way and outputs clear help/usage information. One of the commands which the unix shells support is “GetOpt” which’s a in-built command, which can be used to parse arguments & options provided to it. However, it’s not as user-friendly and feature rich as GetOpts function supported by programming languages like Perl, which can not only parse the options & arguments but also can store the values of some of those options in variables with intuitive names.
As an example, let’s say you are developing a bash shell-script ‘sample.sh’ which you want it to support 3 options:
- –help or -h: For displaying the help message
- –version or -v: For displaying the version information
- –file or -f: For taking the file name as one of the arguments
Ever wondered, how easy it would be, if I can get a template which can:
- Set the variable “opt_help” if either the long option “–help” or short option “-h” is given to the script
- Set the variable “opt_version” if either the long option “–version” or short option “-v” is given to the script
- Set the variable “opt_file” to have the file name as the value stored in it
- Give error message if the user uses the “–file” or “-f” option without an associated file name as the argument
- Give error message if any other option other than the 3 listed above are used
It would make the life of scripting so easy and take away the burden of handling all of these so that you can stay focussed on programming the main task. This is what I have tried to accomplish in the template file below. The ‘main’ function is the one you would use to code the main tasks while the other functions implement what I talked above. You might want to modify the ‘Help’ function to output the appropriate usage information. You might also want to edit the ‘GetOpts’ call on line #191 below to include additional options in the format ‘f|file:\’ at line #194 and so on. The colon ‘:’ after the name of the long option tells the ‘GetOpts’ function that this particular option needs an argument.
Linux:
On Linux OS, the template should work as is without any issues. As the GNU command line toolset which ships with the Linux is one of the best with lots of features.
Mac OS:
On Mac, you need to get the following installed before you could run this template
- First install the Homebrew command. There are plenty of blog posts available on the internet to guide you on how to install home-brew package on Mac
- Once home brew is installed then you need to execute the following commands:
- brew install gnu-getopt
- brew install gnu-sed
- brew install grep
- The above 3 commands would install the GNU version of getopt, sed & grep commands which are needed for this template to work properly
- Lastly, you need to edit your .cshrc file (see here for the blog on cshrc file) to edit the PATH variable as shown below
- setenv PATH /usr/local/opt/grep/libexec/gnubin:/usr/local/opt/gnu-sed/libexec/gnubin:/usr/local/opt/gnu-getopt/bin:${PATH}
- Now you should be all set to use this template on a Mac
Outputs:
I have named this template as sample.sh to run it on the shell.

Output with “–help” or “-h” options

Output with “–version” or “-v” option

Output when a wrong option (say ‘-a’) is given
sample.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | #!/bin/bash #************************************************************# ## $_PGR.sh # ## written by Amjad khan # ## Email: khan.amjadull@gmail.com # ## Phone: +91-9900497591 # ## # ## # ## # #************************************************************# ##************ Define some functions ******## ##----------------- Version? --------------## ## Give the version information and exit ## ## Command line options -v or --version ## ## Exit status is 0 ## ##-----------------------------------------## function version() { VER=$( echo '$Revision$' | sed -e 's/.*: //; s/ .*//; s/\$Revision\$/0.0/' ) YEAR=$( date +%Y) cat <<- ___VERSION_INFO___ $MY_PRG ###utility### $VER Written by Amjad khan Copyright (C) $YEAR - GRAPES PVT LTD All rights reserved. ___VERSION_INFO___ exit 0 } ##----------------- Help ----------------## ## Give the help information and exit ## ## Command line options -h or --help ## ## Exit status is 0 ## ##---------------------------------------## function Help() { cat <<- ___HELP_MESSAGE___ Usage: $MY_PRG [OPTION]... [FILE]... Examples: $MY_PRG # Comments ## ---<description>--- Mandatory arguments to long options are mandatory for short options too. ## ---<explanation for args>--- -h, --help display this help and exit - v , --version output version information and exit ## ---<extra info>--- Report bugs to <khan.amjadull@gmail.com>. ___HELP_MESSAGE___ exit 0 } ##----------------- Cleanup ----------------## ## Clean up temporary files ## ## Exit status is 0 ## ##------------------------------------------## function cleanup_tmpfiles { rm -rf $_TMP } ##--------- Syntax error :( ---------## ## Help to try Help ## ##-----------------------------------## function try_help { # Direct the user to get some help echo "Try \`$MY_PRG --help' for more information" && exit 1 } ##---------------- Getopts ------------------## ## Utility very similar to perl getopts ## ## Can handle long options and set variables ## ##-------------------------------------------## function Getopts(){ declare shorts declare longs declare same declare -a args local index until [ "$1" = "--" ] ; do if echo $1 | grep -q -P '^\S\|\S+:$' ; then shorts=(${shorts[@]} ${1%|*}:) longs=(${longs[@]} ${1 #*|}) same=(${same[@]} $1); elif echo $1 | grep -q -P '^\S\|\S+$' ; then shorts=(${shorts[@]} ${1%|*}) longs=(${longs[@]} ${1 #*|}) same=(${same[@]} $1); elif echo $1 | grep -q -P '^\S+\|\S:$' ; then longs=(${longs[@]} ${1%|*}:) shorts=(${shorts[@]} ${1 #*|}) same=(${same[@]} $1); elif echo $1 | grep -q -P '^\S+\|\S$' ; then longs=(${longs[@]} ${1%|*}) shortss=(${shorts[@]} ${1 #*|}) same=(${same[@]} $1); elif echo $1 | grep -q -P '^\S:?$' ; then shorts=(${shorts[@]} $1); elif echo $1 | grep -q -P '^\S\S+:?$' ; then longs=(${longs[@]} $1); fi shift ; done shift ; shorts=${shorts[@]} longs=${longs[@]} regex=${longs // /\|} regex=${regex // :/\\S*} same=${same[@] // :/} for option in "$@" ; do if echo $option| grep -q -P '^--' ; then echo $option| grep -q -P "^--($regex)\b" [ "$?" = "1" ] && echo "$MY_PRG: unrecognized option '$option'" && return 1; fi done ; regex=$( echo ${same}| sed -e 's: :/;s/\\<:g;s:|:\\>/:g;s:^:\\<:' ) args=($(getopt -l ${longs // /,} -o ${shorts // /,} -n $MY_PRG -s bash -- $@)) [ "$?" = 1 ] && return 1; let index=0; while [ "${args[$index]}" != "--" ]; do if [ ! -z "${args[$index]%%\'*}" ]; then option=$( echo opt${args[$index]}| sed -e "s/$regex/;s/-\+/_/g" ) eval $option=1; else eval $option=${args[$index] // \'/} fi let index+=1 done } ##---------------- main --------------------## ##-------------------------------------------## function main(){ true ; } #*********************************************# ## Some script wide variables MY_PRG=` basename $0` _DATE=` date +%y%m%d%H%M` ## Some global variables declare _TMP; ## Holds temporary files for cleanup ## Valid command line options Getopts \ 'h|help' \ 'v|version' \ -- $@ [ "$?" = "1" ] && try_help; [ ! -z $opt_help ] && Help; [ ! -z $opt_version ] && version; time main; exit ; ################################################### ## $Log$ ################################################### |
Please feel free to reach out with any questions or comment. You can use the Contact Us to write to us.
Related Posts