I take it that the order of the LDIRS and LDFGS is the relevant issue; the additional things the user provides are supposed to end up in the LDFGS (i. e. need to be given after all the LDIRS to /opt/bin/xxx) but don't with your current implementation. So I take it that the -I/xxx arguments are to be added to the LDFGS. If I misunderstood your issue, please state more clearly what you wanted. Otherwise read on.
You have two options to solve an issue like this. Either you implement some kind of intelligence which understands the given options and sorts them properly into the lists where they belong. An approach to this could be like this:
#!/bin/sh
LDIRS="-L/opt/lib"
LDFGS="-llibA -llibB"
PRE=""
for argument in "$@"
do
case "$argument" in
-I*)
LDFGS="$LDFGS $argument"
;;
# other patterns could go here as well
*) # else case
PRE="$PRE $argument"
;;
esac
done
exec /opt/bin/xxx $PRE $LDIRS $LDFGS
As @charles-duffy already pointed out, using a bash or similar which supports proper lists would be way more robust in case any of your arguments contain spaces. If you are sure this won't happen, you should be fine for now. But your code maintainer will hate you for such things when they run into trouble because of this. So here's a less readable version in sh which should take care of this:
#!/bin/sh
LDIRS="-L/opt/lib"
LDFGS="-llibA -llibB"
PRE=""
for argument in "$@"
do
case "$argument" in
-I*)
LDFGS=`printf "%s %q" "$LDFGS" "$argument"`
;;
# other patterns could go here as well
*) # else case
PRE=`printf "%s %q" "$PRE" "$argument"`
;;
esac
done
eval "exec /opt/bin/xxx $PRE $LDIRS $LDFGS"
(Whenever eval is used, a disclaimer needs to be added: eval has it's dangers, some of them security-relevant, so please learn more about it before applying it wildly. The current unmodified case should be fine, though.)
If you think that you have no way of knowing all patterns which are supposed to go into LDFGS, LDIRS, and PRE, you need to hand this over to the user. Unfortunately, then the user needs to know more and pass this information. The calls then will need to look differently.
One way would be this:
#!/bin/sh
LDIRS="-L/opt/lib"
LDFGS="-llibA -llibB"
PRE=""
while [ $# -gt 1 ]
do
case "$1" in
-p) # go into PRE
PRE="$PRE $2"
shift 2
;;
-i) # go into LDIRS
LDIRS="$LDIRS $2"
shift 2
;;
-f) # go into LDFGS
LDFGS="$LDFGS $2"
shift 2
;;
*)
echo "Not understood: $1"
exit 1
;;
esac
done
eval "exec /opt/bin/xxx $PRE $LDIRS $LDFGS"
Now the call needs to look like this:
compiler -p "-o in_file.xx" -f "-I/xxx -I/xxx"
And again, if you have spaces issues, you should consider using proper array solutions or at least the ugly workaround I proposed above.
$@has a number of undesirable behaviors. Always use"$@". Similarly, better to use arrays rather than strings when you want to pass a list:ldirs=( -L/opt/lib ); ldfgs=( -llibA -llibB ); ... "${ldirs[@]}" "${ldflgs[@]}"-- that way you aren't subject to string-splitting and glob expansion. See BashFAQ #50 re: why using unquoted expansions for commands (or subsets of commands) is harmful.-xto your shebang, as in#!/bin/sh -x, will give you concrete logging, which is definitely something that would be helpful here.yourprogram -DVERSION="foo 1.2.3"as a concrete example of a place where$@will burn you:-DVERSION=fooand1.2.3will be treated as two separate arguments."$@"has no such issue.:)