Passing arguments by reference

后端 未结 9 1963
挽巷
挽巷 2020-12-01 01:13

I want to ask if it is possible to pass arguments to a script function by reference:

i.e. to do something that would look like this in C++:



        
9条回答
  •  星月不相逢
    2020-12-01 02:01

    Use a helper function upvar:

    # Assign variable one scope above the caller.
    # Usage: local "$1" && upvar $1 value [value ...]
    # Param: $1  Variable name to assign value to
    # Param: $*  Value(s) to assign.  If multiple values, an array is
    #            assigned, otherwise a single value is assigned.
    # NOTE: For assigning multiple variables, use 'upvars'.  Do NOT
    #       use multiple 'upvar' calls, since one 'upvar' call might
    #       reassign a variable to be used by another 'upvar' call.
    # See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference
    upvar() {
        if unset -v "$1"; then           # Unset & validate varname
            if (( $# == 2 )); then
                eval $1=\"\$2\"          # Return single value
            else
                eval $1=\(\"\${@:2}\"\)  # Return array
             fi
        fi
    }
    

    And use it like this from within Newfun():

    local "$1" && upvar $1 new
    

    For returning multiple variables, use another helper function upvars. This allows passing multiple variables within one call, thus avoiding possible conflicts if one upvar call changes a variable used in another subsequent upvar call.

    See: http://www.fvue.nl/wiki/Bash:_Passing_variables_by_reference for helper function upvars and more information.

    The problem with:

    eval $1=new
    

    is that it's not safe if $1 happens to contain a command:

    set -- 'ls /;true'
    eval $1=new  # Oops
    

    It would be better to use printf -v:

    printf -v "$1" %s new
    

    But printf -v cannot assign arrays.

    Moreover, both eval and printf won't work if the variable happens to be declared local:

    g() { local b; eval $1=bar; }  # WRONG
    g b                            # Conflicts with `local b'
    echo $b                        # b is empty unexpected
    

    The conflict stays there even if local b is unset:

    g() { local b; unset b; eval $1=bar; }  # WRONG
    g b                                     # Still conflicts with `local b'
    echo $b                                 # b is empty unexpected
    

提交回复
热议问题