In bash, how to store a return value in a variable?

前端 未结 7 2117
臣服心动
臣服心动 2020-11-29 09:06

I know some very basic commands in Linux and am trying to write some scripts. I have written a function which evaluates the sum of last 2-digits in a 5-digit number. The fun

相关标签:
7条回答
  • 2020-11-29 09:23

    The return value (aka exit code) is a value in the range 0 to 255 inclusive. It's used to indicate success or failure, not to return information. Any value outside this range will be wrapped.

    To return information, like your number, use

    echo "$value"
    

    To print additional information that you don't want captured, use

    echo "my irrelevant info" >&2 
    

    Finally, to capture it, use what you did:

     result=$(password_formula)
    

    In other words:

    echo "enter: "
            read input
    
    password_formula()
    {
            length=${#input}
            last_two=${input:length-2:length}
            first=`echo $last_two| sed -e 's/\(.\)/\1 /g'|awk '{print $2}'`
            second=`echo $last_two| sed -e 's/\(.\)/\1 /g'|awk '{print $1}'`
            let sum=$first+$second
            sum_len=${#sum}
            echo $second >&2
            echo $sum >&2
    
            if [ $sum -gt 9 ]
            then
                   sum=${sum:1}
            fi
    
            value=$second$sum$first
            echo $value
    }
    result=$(password_formula)
    echo "The value is $result"
    
    0 讨论(0)
  • 2020-11-29 09:28

    The answer above suggests changing the function to echo data rather than return it so that it can be captured.

    For a function or program that you can't modify where the return value needs to be saved to a variable (like test/[, which returns a 0/1 success value), echo $? within the command substitution:

    # Test if we're remote.
    isRemote="$(test -z "$REMOTE_ADDR"; echo $?)"
    # Or:
    isRemote="$([ -z "$REMOTE_ADDR" ]; echo $?)"
    
    # Additionally you may want to reverse the 0 (success) / 1 (error) values
    # for your own sanity, using arithmetic expansion:
    remoteAddrIsEmpty="$([ -z "$REMOTE_ADDR" ]; echo $((1-$?)))"
    

    E.g.

    $ echo $REMOTE_ADDR
    
    $ test -z "$REMOTE_ADDR"; echo $?
    0
    $ REMOTE_ADDR=127.0.0.1
    $ test -z "$REMOTE_ADDR"; echo $?
    1
    $ retval="$(test -z "$REMOTE_ADDR"; echo $?)"; echo $retval
    1
    $ unset REMOTE_ADDR
    $ retval="$(test -z "$REMOTE_ADDR"; echo $?)"; echo $retval
    0
    

    For a program which prints data but also has a return value to be saved, the return value would be captured separately from the output:

    # Two different files, 1 and 2.
    $ cat 1
    1
    $ cat 2
    2
    $ diffs="$(cmp 1 2)"
    $ haveDiffs=$?
    $ echo "Have differences? [$haveDiffs] Diffs: [$diffs]"
    Have differences? [1] Diffs: [1 2 differ: char 1, line 1]
    $ diffs="$(cmp 1 1)"
    $ haveDiffs=$?
    $ echo "Have differences? [$haveDiffs] Diffs: [$diffs]"
    Have differences? [0] Diffs: []
    
    # Or again, if you just want a success variable, reverse with arithmetic expansion:
    $ cmp -s 1 2; filesAreIdentical=$((1-$?))
    $ echo $filesAreIdentical
    0
    
    0 讨论(0)
  • 2020-11-29 09:29

    It is easy you need to echo the value you need to return and then capture it like below

    demofunc(){
        local variable="hellow"
        echo $variable    
    }
    
    val=$(demofunc)
    echo $val
    
    0 讨论(0)
  • 2020-11-29 09:40

    Use the special bash variable "$?" like so:

    function_output=$(my_function)
    function_return_value=$?
    
    0 讨论(0)
  • 2020-11-29 09:41

    It's due to the echo statements. You could switch your echos to prints and return with an echo. Below works

    #!/bin/bash
    
    set -x
    echo "enter: "
    read input
    
    function password_formula
    {
            length=${#input}
            last_two=${input:length-2:length}
            first=`echo $last_two| sed -e 's/\(.\)/\1 /g'|awk '{print $2}'`
            second=`echo $last_two| sed -e 's/\(.\)/\1 /g'|awk '{print $1}'`
            let sum=$first+$second
            sum_len=${#sum}
            print $second
            print $sum
    
            if [ $sum -gt 9 ]
            then
               sum=${sum:1}
            fi
    
            value=$second$sum$first
            echo $value
    }
    result=$(password_formula)
    echo $result
    
    0 讨论(0)
  • 2020-11-29 09:44

    Something like this could be used, and still maintaining meanings of return (to return control signals) and echo (to return information) and logging statements (to print debug/info messages).

    v_verbose=1
    v_verbose_f=""         # verbose file name
    FLAG_BGPID=""
    
    e_verbose() {
            if [[ $v_verbose -ge 0 ]]; then
                    v_verbose_f=$(tempfile)
                    tail -f $v_verbose_f &
                    FLAG_BGPID="$!"
            fi
    }
    
    d_verbose() {
            if [[ x"$FLAG_BGPID" != "x" ]]; then
                    kill $FLAG_BGPID > /dev/null
                    FLAG_BGPID=""
                    rm -f $v_verbose_f > /dev/null
            fi
    }
    
    init() {
            e_verbose
    
            trap cleanup SIGINT SIGQUIT SIGKILL SIGSTOP SIGTERM SIGHUP SIGTSTP
    }
    
    cleanup() {
            d_verbose
    }
    
    init
    
    fun1() {
        echo "got $1" >> $v_verbose_f
        echo "got $2" >> $v_verbose_f
        echo "$(( $1 + $2 ))"
        return 0
    }
    
    a=$(fun1 10 20)
    if [[ $? -eq 0 ]]; then
        echo ">>sum: $a"
    else
        echo "error: $?"
    fi
    cleanup
    

    In here, I'm redirecting debug messages to separate file, that is watched by tail, and if there is any changes then printing the change, trap is used to make sure that background process always ends.

    This behavior can also be achieved using redirection to /dev/stderr, But difference can be seen at the time of piping output of one command to input of other command.

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