Bash Functions and Local Variables – CloudSavvy IT


    Shutterstock

    This article will demonstrate how local variables functions are used and created in Bash. Creating Bash functions allows you to make your code more structural, and local variables help with security and avoiding coding mistakes. Dive in!

    What Are Bash Functions?

    Alike to other coding languages, Bash allows you to create functions from within your code or script. A function can be defined to do a specific task, or set of tasks, and can be called easily and readily from within your main code by simply using the name given to the function.

    You can also nest function calls (calling a function from within another function), use local variables within the function and even pass variables back and forth with functions, or via using global variables. Let’s explore.

    Simple Bash Function

    We define a test.sh with our text editor, as follows:

    #!/bin/bash
    
    welcome(){
    echo "welcome"
    }
    
    welcome
    

    Subsequently, we make that file executable by adding the execute (x) property, and execute the script:

    chmod +x test.sh
    ./test.sh
    

    A simple Bash function

    We can see how the script first defines a welcome() function using the Bash idioms function_name(), and {} function wrappers. Finally, we call the function welcome by simply using it’s name, welcome.

    When the script is executed, what happens in the background, is that the function definition is noted, but skipped (i.e. not executed), until a bit lower the function call welcome is hit, and which point the Bash interpreter executes the welcome function and returns to the line directly after the function calls afterwards, which in this case is the end of our script.

    Passing variables to Bash functions

    We define a test2.sh with our favorite text editor (vi ;), as follows:

    #!/bin/bash
    
    if [ -z "${1}" ]; then 
      echo "One option required!"
      exit 1
    fi
    
    func1(){
      echo "${1}"
    }
    
    func2(){
      echo "${2} ${1}"
    }
    
    func1 "${1}"
    func2 "a" "b"
    

    We again make our script executable by using chmod +x test2.sh and execute the same.

    A more advanced Bash function with variable passing

    The resulting output may look interesting, or even confusing at first. However, it is logical and easy to follow. The fist option passed to the script will, globally, be available from within the code as ${1}, except inside functions, where ${1} becomes the first parameter passed to the function, ${2} the second etc.

    In other words, the global ${1} variable (the first option passed to the script from the command line) is not available from within functions, where the meaning of the ${1} variable changes to the first option passed to the function. Think hierarchy, or think about how a function could present a small script by itself and this will soon make sense.

    As a sidenote, one could also use $1 instead of ${1}, but I strongly encourage aspiring Bash coders to always surround variable names with { and }.

    The reason is that sometimes, when using variables in a string for example, the Bash interpreter is not able to see where a variable ends and part of the adjoining text may be taken to be part of the variable name where it is not, leading to unexpected output. It is also cleaner and clearer what the intention is, especially when it comes to arrays and special option flags.

    We thus start our program with the global ${1} variable set to "first". If you look at the calling of func1, you will see that we pass that variable onto the function, thus the ${1} inside the function becomes whatever was in the ${1} of the program, i.e. "first", and this why the first line of output is indeed first.

    We then call func2 and we pass two strings "a" and "b" to the function. These then become the ${1} and ${2} automatically inside the func2 function. Inside the function, we print them in reverse, and our output matches nicely with b a as the second line of output.

    Finally, we also do a check at the top of our script which ensures that an option is actually passed to the test2.sh script by checking if "${1}" is empty or not using the -z test inside the if command. We exit the script with a non-zero exit code (exit 1) to indicate to any calling programs that something went amiss.

    Local variables and returning values

    For our final example, we define a test3.sh script as follows:

    #!/bin/bash
    
    func3(){
      local REVERSE="$(echo "${1}" | rev)"
      echo "${REVERSE}"
    }
    
    INPUT="abc"
    REVERSE="$(func3 "${INPUT}")"
    echo "${REVERSE}"
    

    We again make it executable and execute the script. The output is cba as can be expected by scanning over the code and noting the variable names etc.

    Example with local variables and returning values

    However, the code is complex and takes a little getting used to. Let’s explore.

    First, we define a function func3 in which we create a local variable named REVERSE. We assign a value to it by calling a subshell ($()), and from within this subshell we echo whatever was passed to the function (${1}) and pipe this output to the rev command.

    The rev command prints the input received from the pipe (or otherwise) in reverse. Also interesting to note here is that the ${1} variable remains inside the subshell! It is past integrally.

    Next, still from within the func3 function, we print the output. However, this output will not be sent to the screen, it rather will be captured by our function call itself and thus stored within the ‘global’ REVERSE variable.

    We set our input to "abc", call the func3 function again from within a subshell, passing the INPUT variable, and assign the output to the REVERSE variable. Note that there is absolutely no connection between the ‘global’ REVERSE variable and the local REVERSE variable inside the script.

    Whilst any global variable, including any REVERSE will be passed to the function, as soon as a local variable is defined with the same name, the local variable will be used. We can also prove and see this another small script test4.sh:

    #!/bin/bash
    
    func3(){
      local REVERSE="$(echo "${1}" | rev)"
      echo "${REVERSE}"
    }
    
    INPUT="abc"
    REVERSE="test"
    func3 "${INPUT}"
    echo "${REVERSE}"
    

    Bash function and local variable example exemplifying two of the learning points seen so far

    When executed the output is cba and test. The cba is this time generated by the same echo "${REVERSE}" inside the func3 function, but is this time output directly instead of captured in the code below as the func3 "${INPUT}" function is not called from within a subshell.

    This script highlights two learning points we covered earlier: firstly, that – even though we set the REVERSE variable to "test" inside the script before calling the func3 function – that the local variable REVERSE takes over and is used instead of the ‘global’ one.

    Secondly, that our ‘global’ REVERSE variable retains it value even though there was a local variable with he same name used from within the called function func3.

    Wrapping Up

    As you can see, Bash functions, the passing of variables, as well as the use of local and semi-global variables makes the Bash scripting language versatile, easy to code, and gives you the possibility to define well structured code.

    Also noteworthy to mention here is that besides improved code readability and easy-of-use, using local variables provides additional security as variables will not be accessible outside of the context of a function etc. Enjoy functions and local variables whilst coding in Bash!

    If you’re interested in learning more about Bash, checkout our How to Correctly Parse File Names in Bash, and Using xargs in Combination With bash -c to Create Complex Commands.



    Source link

    Previous articleQuant (QNT) token is being adopted by firms, banks, and governments
    Next article2021 Kia Seltos S Turbo AWD Review – Routine Competence