How to modify a global variable within a function in bash?

后端 未结 8 2108
情深已故
情深已故 2020-12-02 09:20

I\'m working with this:

GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

I have a script like below:

#!/bin/bas         


        
相关标签:
8条回答
  • 2020-12-02 09:21

    What you are doing, you are executing test1

    $(test1)

    in a sub-shell( child shell ) and Child shells cannot modify anything in parent.

    You can find it in bash manual

    Please Check: Things results in a subshell here

    0 讨论(0)
  • 2020-12-02 09:27

    You can always use an alias:

    alias next='printf "blah_%02d" $count;count=$((count+1))'
    
    0 讨论(0)
  • 2020-12-02 09:29

    When you use a command substitution (ie the $(...) construct), you are creating a subshell. Subshells inherit variables from their parent shells, but this only works one way - a subshell cannot modify the environment of its parent shell. Your variable e is set within a subshell, but not the parent shell. There are two ways to pass values from a subshell to its parent. First, you can output something to stdout, then capture it with a command substitution:

    myfunc() {
        echo "Hello"
    }
    
    var="$(myfunc)"
    
    echo "$var"
    

    Gives:

    Hello
    

    For a numerical value from 0-255, you can use return to pass the number as the exit status:

    mysecondfunc() {
        echo "Hello"
        return 4
    }
    
    var="$(mysecondfunc)"
    num_var=$?
    
    echo "$var - num is $num_var"
    

    Gives:

    Hello - num is 4
    
    0 讨论(0)
  • 2020-12-02 09:30

    It's because command substitution is performed in a subshell, so while the subshell inherits the variables, changes to them are lost when the subshell ends.

    Reference:

    Command substitution, commands grouped with parentheses, and asynchronous commands are invoked in a subshell environment that is a duplicate of the shell environment

    0 讨论(0)
  • 2020-12-02 09:34

    I had a similar problem, when I wanted to automatically remove temp files I had created. The solution I came up with was not to use command substitution, but rather to pass the name of the variable, that should take the final result, into the function. E.g.

    #! /bin/bash
    
    remove_later=""
    new_tmp_file() {
        file=$(mktemp)
        remove_later="$remove_later $file"
        eval $1=$file
    }
    remove_tmp_files() {
        rm $remove_later
    }
    trap remove_tmp_files EXIT
    
    new_tmp_file tmpfile1
    new_tmp_file tmpfile2
    

    So, in your case that would be:

    #!/bin/bash
    
    e=2
    
    function test1() {
      e=4
      eval $1="hello"
    }
    
    test1 ret
    
    echo "$ret"
    echo "$e"
    

    Works and has no restrictions on the "return value".

    0 讨论(0)
  • 2020-12-02 09:39

    A solution to this problem, without having to introduce complex functions and heavily modify the original one, is to store the value in a temporary file and read / write it when needed.

    This approach helped me greatly when I had to mock a bash function called multiple times in a bats test case.

    For example, you could have:

    # Usage read_value path_to_tmp_file
    function read_value {
      cat "${1}"
    }
    
    # Usage: set_value path_to_tmp_file the_value
    function set_value {
      echo "${2}" > "${1}"
    }
    #----
    
    # Original code:
    
    function test1() {
      e=4
      set_value "${tmp_file}" "${e}"
      echo "hello"
    }
    
    
    # Create the temp file
    # Note that tmp_file is available in test1 as well
    tmp_file=$(mktemp)
    
    # Your logic
    e=2
    # Store the value
    set_value "${tmp_file}" "${e}"
    
    # Run test1
    test1
    
    # Read the value modified by test1
    e=$(read_value "${tmp_file}")
    echo "$e"
    

    The drawback is that you might need multiple temp files for different variables. And also you might need to issue a sync command to persist the contents on the disk between one write and read operations.

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