LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Global variables in bash (https://www.linuxquestions.org/questions/programming-9/global-variables-in-bash-4175700367/)

ychaouche 09-08-2021 10:50 AM

Global variables in bash
 
Dear LQ,

What is the "standard" way of programming in bash ? can my functions simply
change global variables inside their code and the rest of my script expects
global variables to be changed anytime, or do you write functions that take
parameters and return values ?

It is easy to receive or return a number or a string, but I still have to figure out how to receive/return multiple values.

pan64 09-08-2021 11:19 AM

in bash you cannot return multiple values, or at least not recommended.
Better to use global variables.
you might want to start here: https://www.thegeekstuff.com/2010/05/bash-variables/ (or a similar page)

teckk 09-08-2021 01:01 PM

Code:

#!/usr/bin/bash

#global vars
a="cow"
b=3

funct1() {
    #local vars
    c="dog"
    d="cats"
    e="frog"
   
    #local var
    echo ""$e" > local var in funct1"
   
    #global var
    echo ""$a" > global var in funct1"
   
    #global var + local var
    f=2
    g=$(($b + $f))
}

funct2() {
    # f from funct1
    str="Mary had "$f" little lambs"
}

echo ""$a" > global var"

funct1
echo ""$c" > from funct1"
echo ""$g" > math from funct1"
echo "John likes "$d""

funct2
echo ""$str" > from funct2"

c="horses"
echo ""$c" > var c changed"

Code:

bash ./test2.sh
cow > global var
frog > local var in funct1
cow > global var in funct1
dog > from funct1
5 > math from funct1
John likes cats
Mary had 2 little lambs > from funct2
horses > var c changed


Keith Hedger 09-08-2021 02:42 PM

basically all variables in BASH are global except variables declared as 'local' in functions, and also parameters passed to functions ( $1 .. $n ).

rnturn 09-08-2021 04:14 PM

Quote:

Originally Posted by ychaouche (Post 6282640)
Dear LQ,

What is the "standard" way of programming in bash ? can my functions simply
change global variables inside their code and the rest of my script expects
global variables to be changed anytime, or do you write functions that take
parameters and return values ?

I use global variables but normally try to limit myself to using them as a global switch, say, "DEBUG=1" to turn extra messages on/off or enable/disable certain bits of code. Otherwise, I use functions though there are times when that's not always doable. If I find myself needing to return multiple values, I resort to global variables... or re-think my code so I can avoid that. Some years ago, I ran across a way to pass and return arrays to/from a shell function but it seemed so clunky and the syntax started to look like line noise on a dial-up connection. I'm not sure why it seemed like such a great idea at the time but, nowadays, feel like it's a technique best forgotten in the name of maintainability. I doubt I'd use it often enough for it to become second nature. Anyway... the folks over at Stack Overflow cover this occasionally. Worth a look if you're interested.

Quote:

It is easy to receive or return a number or a string, but I still have to figure out how to receive/return multiple values.
See above. I dislike turning shell scripts into a big "everything's global" BASIC programs. However, returning values from a function does often make debugging a bit tricky. I'll forget to send debugging messages to stderr at least once during the development and wonder why the function is returning something that's all wrong.

Cheers...

rnturn 09-08-2021 04:18 PM

Quote:

Originally Posted by Keith Hedger (Post 6282683)
basically all variables in BASH are global except variables declared as 'local' in functions, and also parameters passed to functions ( $1 .. $n ).

I have, in the past, made uniquely-named shell variables inside functions to be used while they execute. Then include "unset ..." to destroy them before returning so they've no longer around for any other code to access.

ondoho 09-09-2021 12:56 AM

^ I believe variables in functions are by default local unless they have been defined in the main script, and are unset once the function returns.wrong!

I once read a genius bit of advice, is to set a global RETVAL variable to avoid running functions in subshells, so instead of
Code:

do_func() { echo bla; }
string="$(do_func)"

You would do
Code:

RETVAL=""
do_func() { RETVAL=bla; }
do_func
string="$RETVAL"


ychaouche 09-09-2021 03:16 AM

@ondoho yes, some bash builtins like read and select put their output in $REPLY.

pan64 09-09-2021 03:36 AM

Quote:

Originally Posted by ondoho (Post 6282762)
^ I believe variables in functions are by default local unless they have been defined in the main script, and are unset once the function returns.

I once read a genius bit of advice, is to set a global RETVAL variable to avoid running functions in subshells, so instead of
Code:

do_func() { echo bla; }
string="$(do_func)"

You would do
Code:

RETVAL=""
do_func() { RETVAL=bla; }
do_func
string="$RETVAL"


yes, that would be a good (or better?) approach, just the problem is if the func failed somehow and RETVAL still has a value. But anyway shell is not meant to do difficult/complex data manipulation.

ychaouche 09-09-2021 03:40 AM

@pan64 good point, which makes the function responsible to unset it or to set
it to some conventional NULL value that the caller must check before proceeding.

pan64 09-09-2021 03:53 AM

Quote:

Originally Posted by ychaouche (Post 6282790)
@pan64 good point, which makes the function responsible to unset it or to set
it to some conventional NULL value that the caller must check before proceeding.

the usual way is to use exit/return codes to know if a call was executed successfully. (exit code for apps, return code for funcs).
And yes, you can unset that variable too.

ychaouche 09-09-2021 03:54 AM

So that would be checking $? everytime you call a function ? (if you
want to get defensive).

pan64 09-09-2021 03:57 AM

yes, that is the way - if you want to be on the safe side. But also you need to implement error handling in your functions, otherwise it is just pointless.

grail 09-09-2021 06:32 AM

I would like to clarify that ALL variables not declared as local (in a function) are global to script and ONLY variables declared with local will stay that way inside the function.
Quick example:
Code:

#!/usr/bin/env bash

f()
{
        local v1 v2 # these are the only local variables

        v1=hello
        v2=world
        v3=jiminy

        echo Inside function
        echo "$v1 -- $v2 -- $v3"
}

echo outside function with no changes
f

echo "$v1 -- $v2 -- $v3"

v1=blue

echo outside function after creating new global var v1 and assigning value
echo "$v1 -- $v2 -- $v3"

f

You will see from the output that v1/v2 are only available inside the function and after creating a new v1 outside the function it does not affect the local v1 inside the function


The above being the case, my default is to create sparing global variables and all others are local to their respective functions, even to the extent of having a main() function which is ultimately
one of the only things actually called by the script:
Code:

shebang

# the small number of global variables
declare gvar1 gvar2

func1()
{
  local lvar1 lvar2 pvar1 pvar2 # l for local and p for variables passed to function
...
}

...

main()
{
}

main "$@"

exit 0

These would be the stubs of my general format

ondoho 09-09-2021 11:34 PM

Quote:

Originally Posted by pan64 (Post 6282788)
yes, that would be a good (or better?) approach, just the problem is if the func failed somehow and RETVAL still has a value.

Well that's just general quality control, you should always take care of these things, no matter the language/style you're coding in.

I just wanted to throw it in there; avoiding subshells is a bit of a pet peeve of mine. CPUs are so powerful nowadays people forget how to code as efficiently as possible.


All times are GMT -5. The time now is 04:16 AM.