Why does typeset has different results on bash and ksh when used inside/out of a function?

275 Views Asked by At

Code:

#test.sh
test_func(){
var1="$1"
var2="$1"
echo "var1 before typeset: $var1"
echo "var2 before typeset: $var2"
typeset -l var1="$1"
typeset -l var2
echo "var1 after typeset: $var1"
echo "var2 after typeset: $var2"
}

test_func "$1"

var1="$1"
var2="$1"
echo "var1 before typeset: $var1"
echo "var2 before typeset: $var2"
typeset -l var1=$1
typeset -l var2
echo "var1 after typeset: $var1"
echo "var2 after typeset: $var2"

output using bash with input SAMPLE_INPUT:

var1 before typeset: SAMPLE_INPUT
var2 before typeset: SAMPLE_INPUT
var1 after typeset: sample_input
var2 after typeset: 
var1 before typeset: SAMPLE_INPUT
var2 before typeset: SAMPLE_INPUT
var1 after typeset: sample_input
var2 after typeset: SAMPLE_INPUT

output using ksh:

var1 before typeset: SAMPLE_INPUT
var2 before typeset: SAMPLE_INPUT
var1 after typeset: sample_input
var2 after typeset: sample_input
var1 before typeset: sample_input
var2 before typeset: sample_input
var1 after typeset: sample_input
var2 after typeset: sample_input

I dont understand why bash clobbers var2 in a function and why ksh changing the variable inside a function affects the value of it outside the function when re grabbing the value from $1. I assume this has something to do with their implementation of local vs global variables.

my desired output would be the same on bash and ksh and inside/outside of a function:

var before typeset: SAMPLE_INPUT
var after typeset: sample_input

used out of function:

var before typeset: SAMPLE_INPUT
var after typeset: sample_input
1

There are 1 best solutions below

3
Charles Duffy On BEST ANSWER

In bash, typeset is an alias for declare, which makes variables local when invoked inside a function unless the argument -g is added.

In ksh, typeset has different behavior depending on how you defined your function: With test_func() { ... } variables created with typeset are global; with function test_func { ... } they're local. Because you're using the test_func() { syntax, in your ksh code, typeset refers to the preexisting global variable instead of creating a local; so the original value is retained.

If you want identical behavior, you need to move typeset outside of the function, or add -g when the shell is bash; the latter can be done with a parameter expansion that emits -g only when BASH_VERSION is set, as below:

test_func(){
  var="$1"
  echo "var before typeset: $var"
  typeset ${BASH_VERSION+-g} -l var="$1"
  echo "var after typeset: $var"
}

var="SAMPLE_INPUT"
test_func "$var"
echo "var after function: $var"

...properly emits:

var after function: sample_input

...even on bash.


As for the empty value, you get that even on ksh if you change your function declaration syntax to make typeset create locals by default:

function test_func {
  typeset -l var
  var="$1"
}

test_func "SAMPLE_INPUT"
echo "Result is: <$var>"

...emits, Result is: <> when run in ksh.