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 --.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.