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

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
sachin sarangamath
  • 435
  • 2
  • 6
  • 13
  • `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`. – Charles Duffy Feb 12 '18 at 16:04
  • 1
    BTW, using all-caps names for your own variables is bad form -- see http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, 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. – Charles Duffy Feb 12 '18 at 16:05
  • If you're using `bash`, the `sh` tag should be removed. – Charles Duffy Feb 12 '18 at 16:06
  • ...anyhow, I don't know why you think it should print only `dhoni` `kohli`. That's not what a plain reading of the code *does*. – Charles Duffy Feb 12 '18 at 16:06
  • ok i will do that , but for the time being shall we concentrate on finding the logic for achieving the required thing – sachin sarangamath Feb 12 '18 at 16:07
  • 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). – Charles Duffy Feb 12 '18 at 16:08
  • yes , the logic should print dhoni and kohli and my logic is not working fine because of which i have posted the query , if the logic is working why would have been i posted here – sachin sarangamath Feb 12 '18 at 16:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/164979/discussion-between-sachin-sarangamath-and-charles-duffy). – sachin sarangamath Feb 12 '18 at 16:11
  • 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. – jthill Feb 12 '18 at 16:11
  • @jthil i have respect for everyones valuable time for being spent here – sachin sarangamath Feb 12 '18 at 16:15

2 Answers2

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
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • 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 – sachin sarangamath Feb 12 '18 at 16:17
  • 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. – Charles Duffy Feb 12 '18 at 16:22
  • 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. – Charles Duffy Feb 12 '18 at 16:24
  • or is there any other way apart from getopts with which i can achieve the required thing – sachin sarangamath Feb 12 '18 at 16:24
  • If you want to roll your own command-line parsing, see [BashFAQ #35](http://mywiki.wooledge.org/BashFAQ/035). 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? – Charles Duffy Feb 12 '18 at 16:25
  • You might also want [processing command line options with multiple arguments in bash](https://stackoverflow.com/questions/46394825/processing-command-line-options-with-multiple-arguments-in-bash), or [retrieving multiple arguments for a single option using getopts in bash](https://stackoverflow.com/questions/7529856/retrieving-multiple-arguments-for-a-single-option-using-getopts-in-bash). – Charles Duffy Feb 12 '18 at 16:26
  • actually my requirement i am executing shell which has 2 options say -d -n myscript.sh -d /root/ -n dhoni kohli at one time user may execute the script without passing second arguement like myscript.sh -d /root/ and he also my execute script like myscript.sh -d /root/ -n dhoni kohli then i want to store names after -n in one array – sachin sarangamath Feb 12 '18 at 16:27
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.

jthill
  • 55,082
  • 5
  • 77
  • 137
  • thanks for the comment , can u please suggest me how can i get the required output as posted above – sachin sarangamath Feb 12 '18 at 15:54
  • 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 "$@"` – jthill Feb 12 '18 at 15:57
  • 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 – sachin sarangamath Feb 12 '18 at 16:02
  • 1
    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 :-) – jthill Feb 12 '18 at 16:05