How to pass the getopts processed variable "${@}" to a function? It contains a list of package names needed in various functions.
Seems the issue I have is due to the order of the script, with the processed "${@}" falling after the unprossed "${@}".
I've been manually parsing options in the script which was pretty straight forward, but would like to figure out how to use getopts.
It is hard to give you a sample script that uses getopts correctly to do whatever it is that you're trying to do when you haven't given us any description of what it is that you're trying to do. The while loop running:
Code:
getopts " S " opt
is telling us that the script that you're running uses three characters as option "letters". Two of those option letters are the <space> character and one is the character S. None of those options take an option argument. And, since none of those options take an option argument and your 1st operand to getopts does not have a <colon> as its first character, the OPTARG variable will be unset whenever optargs sets your opt variable to a <question-mark>; but your code assumes that OPTARG will be set to the unknown option letter instead of optargs internally printing a diagnostic message in this case).
In addition to using variables that are explicitly unset in the conditions in which you're using them, your code is also using values assigned to variables before any value has been assigned to them.
When your code detects that a -S option was specified on its command line, it abandons command-line option processing and immediately calls the testfunc function with all of the arguments passed to your script and an additional argument that is set to an empty string. This is highly unusual behavior and is almost always wrong; but since you haven't said what your script is supposed to do, it is impossible to determine what changes, if any, should be made.
On lacking details, sorry. I'll attempt to be more concise and provide enough details so questions can be answered. The previous script posted was only an exersize used to help me understand how getopts works via hands on testing. I was not understanding how it worked after reading the man page and other sources of info. I'm not educated or work in anything related to Unix or Linux. I'm only an aspiring hobbyist Linux user with the goal of obtaining enough of a grasp on shell scripting to contribute something meaningful enough to be considered for use by others.
Add info:
linux 4.14.12-1
bash 4.4.012-2
gawk 4.2.0-2
sed 4.4-1
I currently have a wrapper script (see below), that is parsing options based on positional parameters only. The script is used to automate some tasks that can be performed manually, dealing with building and installing packages from pre made "PKGBUILD" build scripts.
As a learning exercise on getopts usage, at this point I'd like to build a "drop in replacement" using getopts, to replace the manual option parsing in my existing script. This makes it necessary to reprocess multiple letter options after getopts, per the example posted below.
After I get my head around getopts, etc, I'll likely need to completely rewrite the script as it seems getopts usage would pretty much dictate how a script is written, unless I'm missing something.
I have experimented with testing the $OPTARG variable, but it seems to create more issues to work around in my use case than just not using it. I decided instead to focus on using the package list provided by the double quoted $@ parameter after being processed by getopts.
Although my script does not currently handle multiple packages per run, I'd like to include this ability with the eventual proper implementation of getopts.
There are undoubtedly too many errors in the scripts below to discuss at this time. I'd prefer focusing on getting answers to following questions please, unless there is obviously something important that I am missing, (as in spaces being included as options). Thanks and I was not aware of that.
1) How to pass a variable from a script to a function? Is it possible?
2) Best way to get "Package List" contents into the function per below sample test script? I've tried many ways, unsuccessfully as below. The only method working so far is to write the parameter contents to a file, then read it in the function, per post #1 test script above. I could also use awk, etc to filter the variable parameters each time I need the packages in a function, but seems there has to be a more efficient method.
Code:
#!/bin/bash
testfunc () {
echo "Package List : ${@}"
echo ===============================
}
while getopts "S" opt; do
case $opt in
S) testfunc "${@}"
;;
\?) echo "Invalid option: -$OPTARG"
;;
esac
done
shift $(($OPTIND -1))
echo "Package List : ${@}"
What I have so far for a "getopts drop in replacement" to replace the manual option parsing in script below.
Code:
#!/bin/bash
anyfunc () {
prgs=$(< /tmp/prgs)
echo "
Function
\$@ : ${@}
\$progs : $progs
\$prgs : $prgs
"
echo ========================================
}
while getopts "SvfRCDFsph" opt; do
case $opt in
S) S=S ; anyfunc "${@}" "$progs" ;;
v) v=v ; ;;
f) f=f ; ;;
R) R=-R ; ;;
C) C=-C ; ;;
D) D=-D ; ;;
F) F=-F ; ;;
s) s=-s ; ;;
p) p=-p ; ;;
h) h=-h ; ;;
\?) echo "Invalid option: -$OPTARG" ;;
esac
done
shift $(($OPTIND -1))
## ERROR
if [[ $f = f ]] && [[ $v = v ]]; then S=E ; v= ; f= ; echo " Option Errors" ; fi
if [[ -z $S ]] && [[ $v = v ]]; then S=E ; v= ; echo " Option Errors" ; fi
if [[ -z $S ]] && [[ $f = f ]]; then S=E ; f= ; echo " Option Errors" ; fi
## -Sv
if [[ $v = v ]] && [[ $S = S ]]; then S=-Sv ; v= ; fi
## -Sf
if [[ $f = f ]] && [[ $S = S ]]; then S=-Sf ; f= ; fi
## -S
if [[ -z $v ]] && [[ $S = S ]]; then S=-S ; v= ; fi
if [[ -z $f ]] && [[ $S = S ]]; then S=-S ; f= ; fi
## RUN ###=====================================
if [[ $S = -S ]]; then echo " run : install function" ; fi
if [[ $S = -Sv ]]; then echo " run : update function " ; fi
if [[ $S = -Sf ]]; then echo " run : force function " ; fi
progs="${@}"
echo "
S : $S
v : $v
f : $f
R : $R
C : $C
D : $D
F : $F
s : $s
p : $p
h : $h
\$@ : ${@}
\$progs : $progs
"
echo "${@}" >/tmp/prgs
Some test results of "getopts drop in replacement" above.
$ getopz -S pkg1 pkg2
Code:
$ getopz -S pkg1 pkg2
Function
$@ : -S pkg1 pkg2
$progs :
$prgs : - S pkg1 pkg2
========================================
run : install function
S : -S
v :
f :
R :
C :
D :
F :
s :
p :
h :
$@ : pkg1 pkg2
$progs : pkg1 pkg2
$ getopz -Sv pkg1 pkg2
Code:
$ getopz -Sv pkg1 pkg2
Function
$@ : -Sv pkg1 pkg2
$progs :
$prgs : pkg1 pkg2
========================================
run : update function
S : -Sv
v :
f :
R :
C :
D :
F :
s :
p :
h :
$@ : pkg1 pkg2
$progs : pkg1 pkg2
$ getopz -S -v pkg1 pkg2
Code:
$ getopz -S -v pkg1 pkg2
Function
$@ : -S -v pkg1 pkg2
$progs :
$prgs : pkg1 pkg2
========================================
run : update function
S : -Sv
v :
f :
R :
C :
D :
F :
s :
p :
h :
$@ : pkg1 pkg2
$progs : pkg1 pkg2
$ getopz -v -S pkg1 pkg2
Code:
$ getopz -v -S pkg1 pkg2
Function
$@ : -v -S pkg1 pkg2
$progs :
$prgs : pkg1 pkg2
========================================
run : update function
S : -Sv
v :
f :
R :
C :
D :
F :
s :
p :
h :
$@ : pkg1 pkg2
$progs : pkg1 pkg2
$ getopz -vS pkg1 pkg2
Code:
$ getopz -vS pkg1 pkg2
Function
$@ : -vS pkg1 pkg2
$progs :
$prgs : pkg1 pkg2
========================================
run : update function
S : -Sv
v :
f :
R :
C :
D :
F :
s :
p :
h :
$@ : pkg1 pkg2
$progs : pkg1 pkg2
$ getopz -v -S pkg1 pkg2
Code:
$ getopz -v -S pkg1 pkg2
Function
$@ : -v -S pkg1 pkg2
$progs :
$prgs : pkg1 pkg2
========================================
run : update function
S : -Sv
v :
f :
R :
C :
D :
F :
s :
p :
h :
$@ : pkg1 pkg2
$progs : pkg1 pkg2
$ getopz -v -Sf pkg1 pkg2
Code:
$ getopz -v -Sf pkg1 pkg2
Function
$@ : -v -Sf pkg1 pkg2
$progs :
$prgs : pkg1 pkg2
========================================
Option Errors
S : E
v :
f :
R :
C :
D :
F :
s :
p :
h :
$@ : pkg1 pkg2
$progs : pkg1 pkg2
$ getopz -Sf pkg1 pkg2
Code:
$ getopz -Sf pkg1 pkg2
Function
$@ : -Sf pkg1 pkg2
$progs :
$prgs : pkg1 pkg2
========================================
run : force function
S : -Sf
v :
f :
R :
C :
D :
F :
s :
p :
h :
$@ : pkg1 pkg2
$progs : pkg1 pkg2
$ getopz -v pkg1 pkg2
Code:
$ getopz -v pkg1 pkg2
Option Errors
S : E
v :
f :
R :
C :
D :
F :
s :
p :
h :
$@ : pkg1 pkg2
$progs : pkg1 pkg2
ETC............
aurt script: Builds and installs AUR packages.
Code:
#!/bin/bash
# aurt 01-10-18 Depencencies: sudo base-devel git cower pacutils
basedir="${HOME}"/z-AUR-Aurt # "${basedir}" = base directory for build
builddir="${HOME}"/z-AUR-Aurt/"${2}" # "${builddir}" = build directory
pdate=$(date '+%Y-%m-%d') # "${pdate}" = todays date
#===================================================== INSTALL =====================================================
install () {
if [[ -z ${2} ]]; then echo "Error: No package"; exit
fi
exec &> >(tee -i "${basedir}/${2}.log")
### Check if package is installed, if yes bypass, if no proceed to next test
### Check if AUR git repo is available, if yes git clone, if no, print massage and exit aurt
if [[ $(pacman -Q "${2}" 2>/dev/null | awk '{print $1}') != "${2}" ]]; then
if [[ -n $(git ls-remote https://aur.archlinux.org/"${2}".git) ]]; then
cd "${basedir}" || exit
git clone --progress https://aur.archlinux.org/"${2}".git #> /dev/null
else
echo; echo "Error: AUR git repo for ${2} is unavailable"; echo; exit
fi
fi
cd "${builddir}" || exit
### Check if package is installed, if yes bypass to check for updates, if no next test
### Check if PKGBUILD is present, if yes run interactive function, build package and exit aurt, if no, display message, exit
if [[ $(pacman -Q "${2}" 2>/dev/null | awk '{print $1}') != "${2}" ]]; then
if [[ -s PKGBUILD ]]; then
### Print info from aurt-help ### Run interactive function
. aurt-help --pkgbuild
stopYesNo
makepkg -si --needed --noconfirm ; exitcode1=$? ; # echo; echo " makepkg pos 1 exit code: $exitcode1"
# echo; echo " ${2} has been installed."; echo; exit
else
echo; echo "Error: PKGBUILD unavailable, to restore, remove then reinstall package with aurt"; echo; exit
fi
fi ### Use git HEAD local vs remote to check update status, if different run checkupdate function, if same display message, exit
if [[ $(git ls-remote https://aur.archlinux.org/"${2}".git HEAD|awk '{print $1}') != $(git -C "${builddir}" rev-parse HEAD) ]]; then
local=$(git -C "${builddir}" rev-parse HEAD) ####| != |#### default present
checkupdate "${@}"
else echo; echo " Local git HEAD : $(git -C "${builddir}" rev-parse HEAD)"
echo " Remote git HEAD : $(git ls-remote https://aur.archlinux.org/"${2}".git HEAD | awk '{print $1}')"; echo
echo " ${2} up to date, nothing to do."
if [[ -n $(echo $exitcode) ]] && [[ $(echo $exitcode) != 0 ]]; then
echo "Aurt detected makepkg in install exited with ERROR (non zero exit code 1: $exitcode1). Read makepkg output to troubleshoot."
echo
else echo "${pdate} installed ${2}" >> "${basedir}"/A-Aurt-Install.log
fi
fi
}
#=================================================== CHECK UPDATE ==================================================
checkupdate () {
local=$(git -C "${builddir}" rev-parse HEAD)
### Check builddir present, if no message & exit aurt
if [[ ! -d ${builddir} ]]; then
echo " Build directory is not present, reinstall package." ; exit
fi
### Check if .git dir available, if yes, git pull & makepkg to get latest available version number
if [[ -d ${builddir}/.git ]]; then
cd "${builddir}" || exit
git pull --progress https://aur.archlinux.org/"${2}".git 2> /dev/null
makepkg -so #2> /dev/null ; exitcode2=$? ; # echo; echo " makepkg pos 2 exit code: $exitcode2"
fi
### Compare local to remote git HEAD numbers, if different, proceed
avalver="$(makepkg --printsrcinfo|awk -F'=' '/pkgver/,/pkgrel/ {print $2}'|tr -d ' '|paste -d'-' - -)"
# avalver="$(makepkg --printsrcinfo 2> /dev/null|sed -n '/\s*pkg[vr]e[rl]/{s/[^=]*= //;H}; ${x;s/\n//;s/\n/-/p}')"
if [[ $(pacman -Q "${2}" | awk '{print $2}') != "${avalver}" ]]; then
####| != |#### default present
### Print info from aurt-help ### Run interactive function ### Build and install package
. aurt-help --pkgbuild
. aurt-help --updates "${2}"
stopYesNo
cd "${builddir}" || exit
makepkg -fsi --needed ; exitcode3=$? ; # echo; echo " makepkg pos 3 exit code: $exitcode3"
echo "updated on ${pdate}" >> "${builddir}"/Aurt-Update.log
echo; echo " ${2} has been updated."; echo
else
echo "checked on ${pdate}" >> "${builddir}"/Aurt-Update.log
. aurt-help --updates "${2}"
echo " ${2} is up to date, Exiting. "; echo
if [[ -n $(echo $exitcode) ]] && [[ $(echo $exitcode) != 0 ]]; then
echo "Aurt detected makepkg in update exited with ERROR (non zero exit code 2&3: $exitcode2 $exitcode3)."
echo
fi
fi
}
#=============================================== FORCE INSTALL UPDATE ==============================================
forcebuild () {
if [[ -z ${2} ]]; then echo "Error: No package"; exit
fi
if [[ -d ${builddir} ]]; then
mv "${builddir}" "${builddir}".aurt-BU
fi
cd "${basedir}" || exit
git clone https://aur.archlinux.org/"${2}".git
cd "${builddir}" || exit
makepkg -fsi
echo; echo " NOTE: If ${builddir} was present, it has been renamed to ${2}.aurt-BACKUP".
}
#=================================================== INTERACTIVE ===================================================
stopYesNo () {
echo " ^ SEE PKGBUILD ABOVE ^ "; echo
echo " Proceed install/update package with[y] / without[n] editing PKGBUILD."
echo " Edit PKGBUILD? [y][yes] / [n][no] "
echo " Note: exit editor upon completion to proceed with update. "; echo
echo " EXIT NOW: Do not install / update. [e][exit]"; echo
while true; do read -r -p " Please Select: [y]/[n]/[e] " yne
case $yne in
y|yes) $EDITOR PKGBUILD; break ;;
n|no) break ;;
e|exit) exit ;;
* ) echo "y-n ?" ;;
esac
done
}
#===================================================== REMOVE ======================================================
remove () {
if [[ -z ${2} ]]; then echo "Error: No package"; exit; fi
exec &> >(tee -i "${basedir}/${2}.log")
echo " NEXT: Runing sudo pacman -Rns --noconfirm ${2}, and sudo rm -fr ${builddir}"; echo
while true; do read -r -p " Proceed? [Y/n] " yn
case $yn in
y|yes) break ;;
n|no) exit ;;
* ) echo "y-n ?" ;;
esac
done
rm -fr "${builddir}"
rm "${basedir}"/"${2}".log
sudo pacman -Rns --noconfirm "${2}"
}
#===================================================== SEARCH ======================================================
search () {
cower -qs --by=name "${2}"
number=$(cower -qs --by=name "${2}" | wc -l)
echo; echo " Found: ${number} packages above with ${2} in name."; echo
echo " If there is an exact match, details shown below. " ; echo
cower -i "${2}"
}
#================================================ DEPENDENCY DETAILS ===============================================
dependencies () {
uXoff=
uXaur=
cower -i --format=%D --listdelim=' ' "${2}" |fmt -1 >/tmp/deps # Get package deps raw list
if [[ ! -s /tmp/deps ]]; then echo "Dependency info for ${2} is unavailable."; exit # exit if no results
fi #
cower -i --format=%M --listdelim=' ' "${2}" |fmt -1 >/tmp/mdeps # Get makedeps raw list
cp /tmp/deps /tmp/mu-allraw # Copy deps to mu-allraw
cat /tmp/mdeps >> /tmp/mu-allraw # Combine deps, mdeps to mu-allraw
awk -F'[<]|>' '{print $1}' /tmp/mu-allraw >/tmp/mu-ans # remove >, <, & all trailing
sort /tmp/mu-ans >/tmp/mu-all # = met & unmet-all sorted # [met unmet all]
pacman -Qq $(</tmp/mu-all) 2>/dev/null >/tmp/m-all # = met-all # [met all]
comm -23 /tmp/mu-all /tmp/m-all >/tmp/u-all # = unmet-all # [ unmet all]
pacinfo --short $(</tmp/u-all) 2>/dev/null >/tmp/u-off-2 # = unmet-official repo (to filter) #
awk -F'/' '/core|extra|community|multilib/ {print $2}' /tmp/u-off-2 >/tmp/u-off-1 # = unmet-official repo (filtering) #
awk 'NF {print $1}' /tmp/u-off-1 >/tmp/u-off # = unmet-official repo (filtered) # [ unmet off]
comm -23 /tmp/u-all /tmp/u-off >/tmp/u-aur # = unmet-aur repo # [ unmet aur]
if (( $(cat /tmp/mu-all|wc -c) > 125 )); then # If list too wide, display as column
cdc="$(cat /tmp/deps |fmt -1)"
else
cdr="$(cat /tmp/deps|fmt -125)"
fi
cmd="$(cat /tmp/mdeps|fmt -125)"
uXoff="$(cat /tmp/u-off|fmt -125)"
uXaur="$(cat /tmp/u-aur|fmt -125)"
. aurt-help --depend "${2}"
#===================================================================================================================
}
updatereport () {
echo
cower -uv; echo
echo " Number of AUR packages installed & checked: $(cower -uv |tee | wc -l)"; echo
}
parametererror () {
echo
echo " Input Error: Please try again or see aurt --help"
}
#================================================== RUN FUNCTIONS ==================================================
if [[ -z "$*" ]]; then aurt-help --header "${@}"
fi
while :; do
case "${1}" in
-S|--install) install "${@}" ;;
-Sc|--checkversion) checkupdate "${@}" ;;
-Sf|--force) forcebuild "${@}" ;;
-R|--remove) remove "${@}" ;;
-C|--checkupdates) updatereport ;;
-D|--dependencies) dependencies "${@}" ;;
-F|--files) pacman -Ql "${2}" ;;
-s|--search) search "${@}" ;;
-p|--pacmanlog) paclog ;;
-h|--help) aurt-help --help "${@}" ;;
-?*) parametererror; aurt-help --header ;;
*) break
esac
shift
done
aurt-help script: Prints user info to screen.
Code:
#!/bin/bash
# aurt-help.1-10-18
header () {
cat << Read-Header
|=====================================================================================|
| Aurt, a tiny AUR helper script. USAGE: \$ aurt [operation] [package] |
|-------------------------------------------------------------------------------------|
| -S Install Or Update -F Files Provided By Pkg NOTES: |
| -Sv Update By Version -s Search For Pkg |
| -Sf Force Install Or Update -p Pacman Log |
| -R Remove Pkg And Bld Dir -h Help leafpad-aurt: lat |
| -C Ck All Pkgs For Updates thunar-base dir: tbd |
| -D Package Dependency Details Orphans: R \$(p -Qtdq) |
|=====================================================================================|
Read-Header
}
help () {
cat << Read-Help
Usage: aurt <operation> [AUR package name]
Operations:
-S = Install and or update package.
-Sv = Check version number status, update.
-Sf = Force install and or update package.
-R = Remove package.
-C = Check all packages for update.
-D = Dependency details for package.
-F = List of files provided by package.
-s = Search for package.
-p = Display pacman.log.
-h = Aurt help, this page.
Overview:
-S Checks if package is installed, builds, installs, else checks for updates and update in this order.
-Sv Check package for updates based on version numbers and update. (See details below)
-Sf Force install or update backs up build directory to /path/[packagename].aurt-BU, re-builds and or re-installs package.
-R Performs pacman -Rns on package and deletes package build directory and log.
-C Displays list of all installed AUR packages and update status via cower.
-D Displays details on package dependencies, installed or not via cower, pacman, pacinfo, and aurt.
-F Displays a list of all the files belonging to a package.
-s Displays list of search results for package and details if match is found via cower.
-p Displays pacman log file.
-h Displays this help page.
-Sv Details: Aurt -S operation makes use of git HEAD local vs remote to check update status.
In case of git related issues preventing update, the -Sv operation should be used,
which bypasses the default, if 'git HEAD [local=remote] exit' test. The -Sv operation
still performs the .SCRINFO version number test to determine if an update is available.
Read-Help
}
updates () {
# local=$(git -C "${builddir}" rev-parse HEAD) # Getting "local" variable prior (~ line 48 aurt) to git pull.
installed=$(pacman -Q "${2}" | awk '{print $2}')
remote=$(git ls-remote https://aur.archlinux.org/"${2}".git HEAD | awk '{print $1}')
cat << Read-updates
------------------------------------------------------------------------
git HEAD status
Local : ${local}
Remote : ${remote}
------------------------------------------------------------------------
Details
Todays date: : ${pdate}
Package : ${2}
Base Directory : ${basedir}
Build directory : ${builddir}
Installed version : ${installed}
Latest available version : ${avalver}
------------------------------------------------------------------------
Read-updates
}
pkgbuild () {
catpkgbuild=$(cat PKGBUILD) # "${pkgbuild}" = used in aurt-help, pkgbuild function
cat << Read-pkgbuild
=========================================================================
START PKGBUILD
=========================================================================
${catpkgbuild}
=========================================================================
END PKGBUILD
=========================================================================
Read-pkgbuild
}
depend () {
cat << Read-deps
----------------------------------------------------------------------------------------------------------------
Package : ${2}
Unmet AUR repo : ${uXaur}
Unmet Official repo : ${uXoff}
Make Dependancies : ${cmd}
Dependancies : ${cdr}
${cdc}
----------------------------------------------------------------------------------------------------------------
Install all required AUR dependencies prior to installing ${1}.
----------------------------------------------------------------------------------------------------------------
Read-deps
}
while :; do
case "${1}" in
--header) header ;;
--help) help ;;
--updates) updates "${@}" ;;
--pkgbuild) pkgbuild ;;
--depend) depend "${@}" ;;
*) break
esac
shift
done
Suggestions for learning more about shell scripting? I tend to learn more using a "hands on" approach than reading at this point. Most of the terse man pages and documentation I find, imply an underlying understanding of terminology and concepts, much of which I currently do not posess.
Thanks for any help.
Last edited by Cody Learner; 01-15-2018 at 03:03 PM..
Reason: spelling, format, misc corrections
The previous script posted was only an exersize used to help me understand how getopts works via hands on testing. I was not understanding how it worked after reading the man page and other sources of info.
OK, this laudable effort deserves an in-depth answer. I will not cover all intricacies of the getopts-routine, though, only the basics.
What getopts does:
getopts provides a standardised way of parsing a commandline. Notice that commands in UNIX (and Linux) get different inputs on their commandline. Consider the following command:
Code:
cp -pr /some/source /some/target
The cp part is easy: it is the name of the command to call.
The -pr is a shorthand for the options-p and -r. Options always influence how a program does its work, but they do not determine what it does. In this example cp (which copies files) is told to preserve the ownership and rights (-p) and to work recursively instead of on individual files, but these two options do not tell cp what to copy and where to put the copies.
This is done in the last part: the arguments. There are two arguments here: the file (or directory) to copy and the destination where this copy should be put to.
To make things a bit more confusing options may have arguments too: they influence hwo the option works. For instance, the GNU-version of grep
Code:
grep -A 3 -i "searchtext" /path/to/file
grep is the name of the called program and it searches for text. the "searchtext" is the text it searches for (the first argument) and /path/to/file is the file in which it should search (the second argument). -i tells grep to search case-insensitive, so that "searchtext", but also "SEARCHtext" or "SeArChTeXt", etc. would equally be found. This is an option without arguments.
That leaves -A 3. -A tells grep to output not only the line where searchtext was found but a number of lines before, to provide context. If a match is found in line 10 also some lines before (9,8,...) will be shown. The 3 is an argument to this option and tells grep to provide exactly 3 lines of context before each match: lines 7, 8 and 9.
OK, after this rather long introduction to establish the correct wording, here is how getopts parses the commandline:
With each call of getopts you get one (exactly ONE!) option from the commandline. You need to react to this option, usually by setting some flags or variables in your script. After the last option getopts will tell you that there are no more and you have to take what you still have left on the commandline as arguments. Furthermore, whenever you call getopts you need to tell it what options you expect on the commandline and if these options take arguments or not.
Let us start with a simple example: The script script1.sh shall understand two options (-x and -y) and both should be optional.
The script is fairly straightforward:
Code:
#! /bin/ksh
typeset chOpt="" # the newly parsed option will land here
while getopts "xy" chOpt ; do
case $chOpt in
x)
echo "called with the -x option"
;;
y)
echo "called with the -y option"
;;
esac
done
Also notice the difference between these two calls:
Code:
script1.sh -xy
script1.sh -yx
There is none, because options should NOT rely on a certain succession. It is possible to do that, but it is considered very bad style. You will notice that -U will produce an error message because U was not in our getopts string. Change this line:
Code:
while getopts "xy" chOpt ; do
to
Code:
while getopts "xyU" chOpt ; do
and the error message will go away because we told getopts that "U" is also a valid option. To be informed about -U being selected like -y or -x you would have to add another branch to the case-statement that handles the output of getopts results:
Code:
#! /bin/ksh
typeset chOpt="" # the newly parsed option will land here
while getopts "xyU" chOpt ; do
case $chOpt in
x)
echo "called with the -x option"
;;
y)
echo "called with the -y option"
;;
U)
echo "-U option now not only supported but informed about"
;;
esac
done
The next level: arguments.
What would the script do about this commandline:
Code:
script1.sh -xU something
Answer:nothing special, because arguments are not handled by the script:
Code:
script1.sh -xU
called with the -x option
-U option now not only supported but informed about
script1.sh -xU something
called with the -x option
-U option now not only supported but informed about
We need to provide some code to deal with arguments. This is where the OPTIND variable comes into play. OPTIND tells us how many options getopts has read. Since we have all the options already worked on, we want only the arguments remain on the commandline. We do that with the keyword shift. Here is example script2.sh:
Code:
#! /bin/ksh
typeset chOpt="" # the newly parsed option will land here
while getopts "xyU" chOpt ; do
case $chOpt in
x)
echo "called with the -x option"
;;
y)
echo "called with the -y option"
;;
U)
echo "-U option now not only supported but informed about"
;;
esac
done
shift $(( OPTIND -1 )) # we shift out all options parsed so far
while [ -n "$1" ] ; do # this leaves the arguments which we deal with here
echo Next argument is: $1
shift
done
Now run that with the commands:
Code:
script2.sh -x first
script2.sh -xU first second third "fourth fifth"
Notice that "fourth fifth" is ONE argument, because we enclosed it in double quotes on the command line.
The highest level: arguments to options.
We finally need to explain how to provide arguments to options. Suppose the following utility with its description:
Code:
script3.sh [-x][-y][-U <some numerical value>]
We have to tell getopts somehow that we expect -U to be accompanied by some numerical value. We do that by adding a colon (":") after the option in the option string (script3.sh):
Code:
#! /bin/ksh
typeset chOpt="" # the newly parsed option will land here
while getopts "xyU:" chOpt ; do
case $chOpt in
x)
echo "called with the -x option"
;;
y)
echo "called with the -y option"
;;
U)
echo "-U option now not only supported but informed about"
echo OPTARG is $OPTARG
;;
esac
done
shift $(( OPTIND -1 )) # we shift out all options parsed so far
while [ -n "$1" ] ; do # this leaves the arguments which we deal with here
echo Next argument is: $1
shift
done
You will notice that -U now accepts an argument but its value is not checked: the numerical value 3 and the string "foobar" are equally allowed. We need to check this for ourselves in the option-handling loop, i.e.:
Code:
#! /bin/ksh
typeset chOpt="" # the newly parsed option will land here
while getopts "xyU:" chOpt ; do
case $chOpt in
x)
echo "called with the -x option"
;;
y)
echo "called with the -y option"
;;
U)
echo "-U option now not only supported but informed about"
if [ -n "$(echo $OPTARG | sed 's/[0-9]//g')" ] ; then
echo "only numerical values allowed!"
fi
;;
esac
done
shift $(( OPTIND -1 )) # we shift out all options parsed so far
while [ -n "$1" ] ; do # this leaves the arguments which we deal with here
echo Next argument is: $1
shift
done
OK, so far as an introduction. I suggest you play around with getopts yourself and see what it does under certain circumstances. If you still have questions don't be shy and ask.
I hope this helps.
bakunin
____________
PS: as a suggestion: "Hands-On KornShell93 Programming", Barry Rosenberg. My favourite book on the topic and a fun read.
Last edited by bakunin; 01-16-2018 at 10:06 AM..
Reason: corrected typos and clarified text
Hello All,
I would like to ask help from you on how to pass variable value from a function that has been called inside the function. I have created below and
put the variables in " ". Is there another way I can do this? Thank you in advance.
readtasklist() {
while read -r mod ver... (1 Reply)
May i please know why is it printing the script name for $0 when i pass those parameters to function.
#!/bin/bash -x
usage()
{
echo "In Usage Function"
echo $0
echo $1
echo $2
}
echo "printing first time"
echo $0
echo $1
echo $2
usage $0 $1 $2
Output: (2 Replies)
The objective of this function is to validate the file full path.
cat /dev/null > crontab_NOTEXISTS.txt
function File_Existence # Accepts 1 parameter
{
file_name="$(echo $1)"
echo "${file_name}"
&& break || echo "$file_name NOT FOUND" >> crontab_NOTEXISTS.txt
}
while read file_name... (7 Replies)
Hi all,
In the given script code .
I want to pass the maximum value that variable "i" will have in function DivideJobs () to variable $max of function SubmitCondorJob().
Any help?
Thanks
#!/bin/bash ... (55 Replies)
Hi All,
I am new to shell scripting required some help in passing the parameter value to the shell script.
I am writing a shell script, in the script I have created two functions as below.
first function
get_trend_ids () {
Here I am connecting to the database and getting all the... (3 Replies)
Hello everyone,
I am curious to find a possible way of doing something like this in ksh:
call a function and have that function set the value of the variable that the function knows by the name of $1....
example:
#! /bin/ksh
set_var(){
case $1 in
var1) this is where I would like to... (7 Replies)
hello,
I got this error while I was trying to start some application in UNIX. It was an AIX 5.0 machine. It was not loading an .so file.Can anyone help me solving this issue...Its urgent please!!!!! (1 Reply)
Hi ,
I have three funcions f1, f2 and f3 .
f1 calls f2 and f2 calls f3 .
I have a global variable "period" which i want to pass to f3 .
Can i pass the variable directly in the definition of f3 ?
Pls help .
sars (4 Replies)
Hi,
I am trying to sum up numbered columns and in order to tidy up the program I have wrote a function to do the adding of some numbers. I have a problem though with passing a variable to the function in the UNIX bash shell. The function only gives the first number in the variable list and does... (4 Replies)
Im running a script that runs scripts within it self and i need to pass vars made in the original script to scripts run within it and the only way i can think to do it is right the string to a file and read the file in the script (4 Replies)