2

i am executing shell script called ./myscript.sh with 2 options like below

./myscript.sh -d /root/ -n "dhoni" "kohli"

first option is -d and value is /root/

second option is -n and values are dhoni and kohli for this in the current example

But each time while executing this script number of names passed to this script for -names option may vary

the code i have written for this is

EMPNAMES=("$@")

while getopts "d:n:" arg; do
   case "$arg" in
      d) PATH="$OPTARG"
      ;;
      n)  EMPNAMES="$OPTARG"
      ;;

for arg in "${EMPNAMES[@]}"; do
  echo "$arg"
done

it should print
dhoni
kohli

But it is printing
dhoni
/root/
-names
dhoni
kohli

11
  • sh, or bash? Please tag only for the one you're actually using to run your script: They're two very different shells, and the syntax you're using isn't available at all with /bin/sh. Commented Feb 12, 2018 at 16:04
  • i am using bash Commented Feb 12, 2018 at 16:05
  • 1
    BTW, using all-caps names for your own variables is bad form -- see pubs.opengroup.org/onlinepubs/9699919799/basedefs/…, fourth paragraph: Such names are used for variables meaningful to the shell or other POSIX-specified tools, whereas lowercase names are reserved for application use. Commented Feb 12, 2018 at 16:05
  • 2
    (f/e, overriding PATH will stop your script from being able to run any external programs, because it's changing the PATH variable used to execute other software; if you named in path instead, you'd avoid that bug). Commented Feb 12, 2018 at 16:08
  • 1
    dude, there are more questions raised by your code than you're seeing, you're missing relevant issues because you're new. have a little respect. Commented Feb 12, 2018 at 16:11

2 Answers 2

2

empnames=( "$@" ) doesn't make sense if you want the array to only contain matches, because you're initializing it to contain every single argument your script was passed at startup. Instead, initialize it to start out empty, and append to it every time you find an appropriate argument.

Note that n: specifies that one argument immediately after -n is a name. If you want to specify two names, put -n before each of them, as follows:

#!/usr/bin/env bash

# set argument list, just as if the script were called with these arguments
set -- -d /root/ -n "dhoni" -n "kohli"

# Initialize your array to start out empty
empnames=( )

while getopts "d:n:" arg; do
   case "$arg" in
      d) path="$OPTARG" ;;
      n) empnames+=( "$OPTARG" ) ;;
   esac
done

for arg in "${empnames[@]}"; do
  echo "$arg"
done

...properly emits:

dhoni
kohli
Sign up to request clarification or add additional context in comments.

7 Comments

thanks for the solution and thanks for ur valuable time for this , but one query , is there any way that i can pass args like set -- -d /root/ -n "dhoni" "kohli" and get the required output
Not that plays nice with the way getopts is supposed to be used. There are some workarounds that are possible, but the better answer is just not to use that convention.
Here's a question -- what do you want to do with names that don't have any flag before them? No -d, no -n, etc.
or is there any other way apart from getopts with which i can achieve the required thing
If you want to roll your own command-line parsing, see BashFAQ #35. If you're doing that, then in the -n case you could just set empnames=( "$@" ); break to assign all remaining arguments to that array and exit the loop. But that would mean that -n would need to be after the -d; are you sure that's what you want?
|
1
      n)  EMPNAMES="$OPTARG"

is assigning to an array, in bash that defaults to the first element of that array, replacing the -d that was there before.

getopts options that take an argument only take one, kohli is left as a main-body argument.

4 Comments

thanks for the comment , can u please suggest me how can i get the required output as posted above
It'd help if you explained the context a bit. As a first cut at it I'd say lose the n option entirely and shift out the options with shift $((OPTIND-1)), then just printf %s\\n "$@"
while executing the script i want to pass 2 names for the option -n , this passed names should be stored in an array in the script
The usual way to do that is to pass both as a single argument and separate them in the arg processing, commas are common, or you could use colon as that's a conventionally-reserved character in paths. Having one option eat two arguments will violate the Principle of Least Surprise :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.