Reputation:
I am getting twice the arguments used with my script :
The first time using this following code, to make sure there isn't arguments that I don't want (I only take in consideration arg1:arg2:arg3)
PARAM=$@
while [ "$#" -gt "0" ]; do
case $1 in
arg1)
shift2
;;
arg2)
shift
;;
arg3)
shift
;;
*)
echo "Usage : ./test.sh arg1 <VAL1> <VAL2> [arg2] [arg3]"
exit 2
;;
esac
shift
done
And I would like to parse those arguments all over again and be able able to get the two following arguments when I get arg1, so I started with something like this :
for command in $PARAM
do
case $command in
arg1)
shift
VALUE1=$command
shift
VALUE2=$command
exec_arg1
;;
esac
shift
But while using "shift", I get the error shift: can't shift that many
The shebang is "#!/bin/sh" and I am looking for a solution without having to use bash's shebang (i.e. "#!/bin/bash")
Upvotes: 1
Views: 725
Reputation: 6577
You cannot concatenate a list to a string and safely turn it back into a list (without a complex helper function). See this FAQ.
shift
behaves differently in different shells. In Bash and Zsh, when no positional parameters remain, shift
simply returns false. Many shells including Dash (contrary to POSIX, perhaps because of ksh behavior) throw a fatal error instead. ksh93 provides a way around this via the command
builtin, but this also appears to be not specified by POSIX, though this workaroud also works in Dash anyway, but not mksh
(there's also a bug in mksh that I just discovered yesterday that prevents this from working, and the maintainer probably won't fix it in a way that allows the workaround). Busybox doesn't follow POSIX either and gives no meaningful exit code.
Anyway, the point is you can't rely upon shift
because so many shells have bugs here. You should iterate arguments without shifting them if possible and test the number of remaining arguments in a way that ensures you aren't shifting over the edge like you're currently doing. I don't think your idea of pre-validating the arguments is better than just validating and parsing at the same time.
#!/bin/sh
f()
if ! ${_called_f+false}; then
while ! ${1+false}; do
case $1 in
arg1)
${3+:} return 1
value1=$2 value2=$3
shift 3
exec_arg1
;;
arg[23])
${2+:} return 1
value1=$1
shift
"exec_arg${value1##"${value1%?}"}" # Only do this crap if restricted to POSIX
;;
*)
return 1
esac
done
else
# Hack nobody will understand since this probably isn't what you want anyway.
_called_f= value1= value2= command eval \
'typeset +x value{1,2} 2>/dev/null; f "$@"'
fi
if ! f "$@"; then
echo 'Error parsing args, exiting...' >&2
exit 1
fi
See also: option parsing
Upvotes: 2