This question already has answers here:
Why does getopts only work the first time?
(2 answers)
Closed 3 years ago.
This is my first attempt using getopts, and so far it hasn't been working for me. The code in my script is:
while getopts "s:" opt; do
case $opt in
s) subj=$OPTARG;;
\?) echo "Incorrect usage";;
esac
done
echo ""
echo $subj
When I try to run to script like this:
myScript.sh -s 100
I want it to echo the subject id number I've specified. So far though it just gives me a blank statement.
getopts uses the current value of OPTIND to know which argument to look at next. If you are using source to run your script, though, OPTIND never gets reset between calls. You probably added subj after the first run, so that its value wasn't set the first time you sourced the script. Explicitly setting OPTIND=1 would fix it.
$ source myScript.sh -s 100
100
$ unset subj; source myScript.sh -s 100
$ OPTIND=1
$ source myScript.sh -s 100
100
Related
This question already has answers here:
Using getopts inside a Bash function
(3 answers)
Closed 3 years ago.
I am unable to parse flags in a function in a bash script.
I have a shell script admin.sh that I'm sourcing (i.e. source ./admin.sh). In that script I have function called command_to_do. The code below shows what I'm trying to accomplish. I want to be able to call command_to_do from the command line and process all arguments
#!/bin/bash
function command_to_do() {
echo "Args $#"
SYSTEM=false
UNINSTALL=false
PUSH=false
VERSION="debug"
while getopts "sup:" opt; do
printf "\n$opt\n"
case $opt in
s) echo "Setting SYSTEM to true"
SYSTEM=true
;;
p) echo "Setting VERSION to $OPTARG"
PUSH=true
VERSION=$OPTARG
;;
u) echo "Setting UNINSTALL to true"
UNINSTALL=true
;;
esac
done
printf "\nSystem: $SYSTEM\nVersion: $VERSION\n"
if [[ $UNINSTALL = true ]]; then
if [[ $SYSTEM = true ]]; then
echo "system uninstall"
else
echo "non-system uninstall"
fi
fi
}
I'm getting very strange results. The first time I run the command_to_do -s -p release, it correctly processes the flags and prints the expected results
Args -s -p release
s
Setting SYSTEM to true
p
Setting VERSION to release
System: true
Version: release
Every time after that, it doesn't seem to capture the flags. For instance, running that same command again gives:
Args -s -p release
System: false
Version: debug
If I remove the function declaration (function command_to_do() {}) and just have the code in the admin.sh file, everything seems to work fine every time, but I have to call the script with the dot syntax (./admin -s -p release). The reasoning behind why I don't want to use the dot syntax is not important. I just want to know if it's possible to do what I'm attempting and how.
I've read about passing the arguments to the function with command_to_do $#, but, as I'm trying to call the function by it's name from the command prompt, this is not applicable and it appears by the echo $# statement that the arguments are being passed to the function.
I'm new to writing bash scripts so any help would be appreciated.
The trick here is resetting OPTIND, which tells getopts where it is in the current argument list. As it is, your first call leaves OPTIND at a value telling getopts not to process the arguments it already saw.
See a demonstration at https://ideone.com/UvUyn2
This question already has answers here:
What is $opt variable for command line parameter in bash
(3 answers)
Closed 4 years ago.
Normally, script parameters are read from $1, $2, ...
Sometimes this is combined with shift and a while-loop and case-statement to process multiple parameters.
while [[ $# > 0 ]]; do
case "$1" in
-v|--verbose)
VERBOSE=1
;;
-d|--debug)
VERBOSE=1
DEBUG=1
;;
*) # unknown option
echo 1>&2 -e "${COLORED_ERROR} Unknown command line option '$key'.${ANSI_NOCOLOR}"
exit 1
;;
esac
shift # parsed argument or value
done
Today, I found a code snippet based on a simple for-loop:
#! /bin/bash
for opt; do
echo $opt
done
Execution:
$ ./test.sh foo bar spam
foo
bar
spam
Normally, one would see for i in ...; do.
Why/how can a simplified for-loop access script parameters?
Does it also work with parameters in functions?
From help for:
If in WORDS ...; is not present, then in "$#" is assumed.
I was trying to modify the bd script to use getopts. I am a newbie at bash scripting
my script is
while getopts ":hvis:d:" opt
do
...
done
...
echo $somedirpath
cd "$somedirpath"
this runs fine when doing
$ ./bd -v -i -s search
or
$ ./bd -is search -d dir
But when running it like this
$ . ./bd -s search
getopts doesn't read the arguments at all. And all the variables I set in the while loop according to the arguments are all not set, so the script no longer works. Please help!
Setting OPTIND=1 before invoking getopts works fine.
The problem is that getopts relies on OPTIND to loop through the arguments provided, and after sourcing the script, it will be set to some value greater than 1 by getopts according to how many arguments you pass. This value gets carried over even after the script ends(because its being sourced). So the next time its sourced, getopts will pick up from that OPTIND, rather than starting from 1!
This might cause strange behaviour with other scripts, and I don't know how safe this is. But it works!
For a better workaround, I think what #tripleee suggests looks safe and robust.
When you source a script, the arguments parsed by getopts are those of the current shell, not the parameters on the source command line.
The common workaround is to have your script merely print the path, and invoke it like cd "$(bd)" instead (perhaps indirectly through a function or alias).
Setting OPTIND=1 may not work reliably on zsh. Try to use something different than getopts:
while [ "$#" -gt 0 ]
do
case "$1" in
-h|--help)
help
return 0
;;
-o|--option)
option
return 0
;;
-*)
echo "Invalid option '$1'. Use -h|--help to see the valid options" >&2
return 1
;;
*)
echo "Invalid option '$1'. Use -h|--help to see the valid options" >&2
return 1
;;
esac
shift
done
This question already has answers here:
Creating bash scripts that take arguments
(3 answers)
Closed 8 years ago.
I am curious as to how to pass in arguments via terminal to the bash script and read them and process the script functions based on the arguments.
So if I did something like:
./scriptname.sh install
#or
./scriptname.sh assets install
How would I say, ok the first argument installs something, while the second sais to do something else based on the first argument.
$0 is the name of the command
$1 first parameter
$2 second parameter
$3 third parameter etc. etc
$# total number of parameters
for args in $*
blah blah
One great way to pass arguments to a script is to use the bash builtin functionality getopts
you can use it like this:
# a script that accepts -h -a <argument> -b
while getopts "ha:b" OPTION
do
case $OPTION in
h)
# if -h, print help function and exit
helpFunction
exit 0
;;
a)
# -a requires an argument (because of ":" in the definition) so:
myScriptVariable=$OPTARG
;;
b)
# do something special
doSomeThingSpecial
;;
?)
echo "ERROR: unknonw options!! ABORT!!"
helpFunction
exit -1
;;
esac
done
You can access a particular argument with $1, $2, ... See eg What does "$1/*" mean in "for file in $1/*"
You can also use "$#" to loop on your arguments. Ex : https://github.com/gturri/dotfiles/blob/master/bootstrap.sh#L64
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I want to make a Pathogen helper script using a .sh file. I know if you make it executable it can be run as a command, but I have no idea how to do -o --options or arguments or anything like that.
Basically that's what I want answered, really all I need to know is how to do something like:
pathogen install git://...
Or something along those lines. Any help is appreciated. :)
The bash builtin getopts does not handle long arg parsing mechanism as far as I know.
getopt(1) is the tool you are looking for.
Not a program entirely, but you'll get the idea
PARSED_OPTIONS=$(getopt -n "$0" -o h123: --long "help,one,two,three:" -- "$#")
while true;
do
case "$1" in
-h|--help)
echo "usage $0 -h -1 -2 -3 or $0 --help --one --two --three"
shift;;
-1|--one)
echo "One"
shift;;
--)
shift
break;;
esac
done
Take a look at code example and explanation given here.
Passing arguments is the easiest of the two (see "What are special dollar sign shell variables?" on SO):
#!/bin/sh
echo "$#"; # total number of arguments
echo "$0"; # name of the shell script
echo "$1"; # first argument
Assuming the file is named "stuff" (sans an extension) and the result of running ./stuff hello world:
3
stuff
hello
To pass in single letter switches (w/ optional associated params), e.g. ./stuff -v -s hello you'll want to use getopts. See "How do you use getopts" on SO and this great tutorial. Here is an example:
#!/bin/sh
verbose=1
string=
while getopts ":vs:" OPT; do
case "$OPT" in
v) verbose=0;;
s) string="$OPTARG";;
esac;
done;
if verbose; then
echo "verbose is on";
fi;
echo "$string";
The line having getopts coupled with while needs further explanation:
while - start the while loop, going through everything getopts returns back after it processes
getopts :vs: OPT; - the program getopts with 2 arguments :vs: and OPT
getopts - returns something while can iterate over
:vs: - the first argument, this describes what switches getopts will look for while it parses the shell line
: - the first colon takes getopts out of debug mode, omit this to make getopts verbose
v - find the switch -v, this will not have an argument after it, just a simple switch
s: - find the option -s with an argument after it
OPT - will store the character used (the name of the switch), e.g. "v" or "s"
OPTARG - the variable to load the value into during each of while's iterations. For v, $OPTARG will not have a value, but for s it will.
The colon : tells getopts to look for an argument after the switch. The only exception is if the sequence of characters starts with : then it toggles getopts in/out of debug/verbose mode. For example:
getopts :q:r:stu:v will take getopts out of debug mode, will tell it that switches q, r, and u will expects args, while s, t, and u won't. This would be applicable for something like: stuff -q hello -r world -s -t -u 123 -v
getopts tuv will only tell getopts to search for switches t, u and v with no arguments, e.g. stuff -t -u -v, and to be verbose