Indirect parameter substitution in shell script

后端 未结 4 636
庸人自扰
庸人自扰 2020-12-21 17:16

I\'m having a problem with a shell script (POSIX shell under HP-UX, FWIW). I have a function called print_arg into which I\'m passing the name of a parameter as $1. Given

相关标签:
4条回答
  • 2020-12-21 17:40

    You could use eval, though using direct indirection as suggested by SiegeX is probably nicer if you can use bash.

    #!/bin/sh
    
    foo=bar
    print_arg () {
        arg=$1
        eval argval=\"\$$arg\"
        echo "$argval"
    }
    print_arg foo
    
    0 讨论(0)
  • 2020-12-21 17:40

    In bash (but not in other sh implementations), indirection is done by: ${!arg}

    Input

    foo=bar
    bar=baz
    
    echo $foo
    echo ${!foo}
    

    Output

    bar
    baz
    
    0 讨论(0)
  • 2020-12-21 17:41

    This worked surprisingly well:

    #!/bin/sh
    foo=bar
    
    print_arg () {
        local line name value
        set | \
        while read line; do
            name=${line%=*} value=${line#*=\'}
            if [ "$name" = "$1" ]; then
                echo ${value%\'}
            fi
        done
    }
    
    print_arg foo
    

    It has all the POSIX clunkiness, in Bash would be much sorter, but then again, you won't need it because you have ${!}. This -in case it proves solid- would have the advantage of using only builtins and no eval. If I were to construct this function using an external command, it would have to be sed. Would obviate the need for the read loop and the substitutions. Mind that asking for indirections in POSIX without eval, has to be paid with clunkiness! So don't beat me!

    0 讨论(0)
  • 2020-12-21 17:47

    Even though the answer's already accepted, here's another method for those who need to preserve newlines and special characters like Escape ( \033 ): Storing the variable in base64.

    You need: bc, wc, echo, tail, tr, uuencode, uudecode

    Example

    #!/bin/sh
    
    
    #====== Definition =======#
    varA="a
    b
    c"
    # uuencode the variable
    varB="`echo "$varA" | uuencode -m -`"
    # Skip the first line of the uuencode output.
    varB="`NUM=\`(echo "$varB"|wc -l|tr -d "\n"; echo -1)|bc \`; echo "$varB" | tail -n $NUM)`"
    
    
    #====== Access =======#
    
    namevar1=varB
    namevar2=varA
    
    echo simple eval:
    eval "echo \$$namevar2"
    echo simple echo: 
    echo $varB
    echo precise echo: 
    echo "$varB"
    echo echo of base64
    eval "echo \$$namevar1"
    echo echo of base64 - with updated newlines
    eval "echo \$$namevar1 | tr ' ' '\n'"
    echo echo of un-based, using sh instead of eval (but could be made with eval, too)
    export $namevar1
    sh -c "(echo 'begin-base64 644 -'; echo \$$namevar1 | tr ' ' '\n' )|uudecode"
    

    Result

    simple eval:
    a b c
    simple echo:
    YQpiCmMK ====
    precise echo:
    YQpiCmMK
    ====
    echo of base64
    YQpiCmMK ====
    echo of base64 - with updated newlines
    YQpiCmMK
    ====
    echo of un-based, using sh instead of eval (but could be made with eval, too)
    a
    b
    c
    

    Alternative

    You also could use the set command and parse it's output; with that, you don't need to treat the variable in a special way before it's accessed.

    0 讨论(0)
提交回复
热议问题