6

I need to read and write the positional parameters $@ of a function's caller. The Bash man page says that:

A shell function is an object that is called like a simple command and executes a compound command with a new set of positional parameters

So $@ is rewritten at every call. I looked for some "special parameter" but found nothing. The shell variable BASH_ARGV seems to solve my problem, however it requires shopt -s extdebug enabled, what isn't the default behavior in my machine neither looks like a option to turn on in production.

extdebug
    If set, behavior intended for use by debuggers is enabled:
    ...
    4.     BASH_ARGC and BASH_ARGV are updated as described in their
           descriptions above.
    ...

Is Bash capable of read or write a function's caller $@ without BASH_ARGV? Do you think that Bash is limited and use another shell for scripting?

Edit: I want a fancy getopt wrapper inside my helper library. So all behavior related to it goes inside a function. No need to check errors or set --.

7
  • How to format the citation block like a man page? Oct 12, 2012 at 2:14
  • 1
    You can just pass the parent $@ explicitly to the function: func "$@".
    – jw013
    Oct 12, 2012 at 2:42
  • And if I need to rewrite it? Oct 12, 2012 at 2:48
  • I don't understand what you are asking. What are you trying to do?
    – jw013
    Oct 12, 2012 at 3:35
  • 3
    Why do you want to do this? Sounds like an XY problem Oct 12, 2012 at 15:55

2 Answers 2

2

A function cannot affect its caller's positional parameters. This is by design: positional parameters are meant to be private to the function.

Make your function work on an array.

myfunction () {
  local _myfunction_arrayname=$1
  shift
  … # work on the positional parameters
  eval "$_myfunction_arrayname=(\"\$@\")"
}
myfunction foo "$@"
set -- "${foo[@]}"

In ksh93 and bash, there's a roundabout way to do something approaching by combining an alias and the . (source) builtin with a process substitution. Example.

alias myfunction='. <(echo myfunction_body \"\$@\"; echo set -- "\"\${new_positional_parameters[@]}\"")'

Put the meat of the work of the function in myfunction_body and make it set the array new_positional_parameters. After a call to myfunction, the positional parameters are set to the values that myfunction_body puts in new_positional_parameters.

0

Here's some code which loops through the parameters, updating each of them as necessary. In this case, replacing duplicate slashes with a single one:

for param
do
    param="$(printf %s. "$1" | tr -s "/")"
    set -- "$@" "${param%.}"
    shift
done
2
  • Off topic question, but why not set -- "${@//\/+(\/)//}" instead of all that? (Note that requires shopt -s extglob, which is off by default for non-interactive shells.)
    – manatwork
    Oct 17, 2012 at 10:06
  • @manatwork Nice one-liner for this specific situation. It's just a (verbose) demonstration of how to do arbitrary modification to the parameters.
    – l0b0
    Oct 17, 2012 at 10:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .