1

I have a bash script which can be passed a number of different arguments and variables to be used by the script itself. Some of the parameters get assigned to variables. The second while loop does not appear to be running when the program tries to execute it. I've simplified the following script for confidentiality/simplicity reasons.

./myscript --dir2 /new/path
while :; do
  case $1 in
    --var1) $var1=$2
    ;;
    --var2) $var2=$2
    ;;
    "") break
  esac
  shift
done

$dir1=/default/directory
$dir2=/default/directory

while :; do
  case $1 in
    --dir1) $dir1=$2
    ;;
    --dir2) $dir2=$2
    ;;
    "") break 
  esac
  shift
done

echo "Expect /default/directory, returned: $dir1" 
echo "Expect /new/path, returned: $dir2"

Here's what my program would effectively return.

Expected /default/directory, returned: /default/directory
Expected /new/path, returned: /default/directory

Is there a better way to go about this? Or another way to iterate over the parameters originally passed to the script? Thanks for the help!

1
  • 2
    Of course it doesn't. You've shifted all the arguments out. Commented Apr 24, 2018 at 22:46

2 Answers 2

2

If you want to preserve your arguments, you can copy them into an array, and then restore the original list from that array later:

#!/usr/bin/env bash
#              ^^^^ - must be invoked as bash, not sh, for array support

# Copy arguments into an array
original_args=( "$@" )

# ...consume them during parsing...
while :; do # ...parse your arguments here...
  shift
done

# ...restore from the array...
set -- "${original_args[@]}"

# ...and now you can parse them again.
Sign up to request clarification or add additional context in comments.

Comments

1

It's because your using shift which consumes the elements. Try using a for loop to iterate over the args. There's a few ways to do this. Here is my preferred method:

for elem in "$@" # "$@" has the elements in an array 
do
   ... # can access the current element as $elem
done

Another way is to access them by index, you can look up a tutorial on bash array syntax for that.

5 Comments

Needs to be in "$@", not in $@ -- without the quotes, you get identical behavior to unquoted $* (effectively concatenating all your arguments into a single string, then splitting that string into words and expanding each word as a glob).
BTW, for elem do will also have this effect -- "$@" is the default thing for a for loop to iterate over.
Follow up question to this answer, what would the syntax be for accessing $elem+1?
@JensPetersen, one can't -- that's a significant downside of this answer. You could iterate by indexes, though -- for ((idx=1; idx<=$#; ++idx)); do elem=${!idx}; next_idx=$((idx + 1)); if (( next_idx <= $# )); then next=${!next_idx}; else next=; fi; printf 'elem=%q next=%q\n' "$elem" "$next"; done
Great to know! Looks like I'm going with the original_args solution. :)

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.