3

I'm having some trouble with trying to evaluate/expand a variable when I define a function in zsh - Is this possible? Example:

variable=foo
mytest(){
  echo ${variable}  
}
mytest           //outputs foo
variable=bar
test           //outputs bar

I want variable inside test() to stay foo and not be affected by $variable anymore. I have been reading the manual and trying eval and different quoting but nothing seems to work.

4
  • You need a local variable so e.g. f_test(){ local var=value; print -l ${var}; } Commented Sep 23, 2018 at 10:19
  • I still need the variable inside the function to be set from the variable outside the function, just not changed after the function is declared
    – Dean
    Commented Sep 23, 2018 at 10:35
  • I don't think you can do that. You should not use a variable name that you want to reuse later for other things.
    – RalfFriedl
    Commented Sep 23, 2018 at 11:39
  • Nope, you'll need a different language. unix.stackexchange.com/questions/94129/…
    – thrig
    Commented Sep 23, 2018 at 14:33

2 Answers 2

1

You want a variable inside your function which, once set, keeps their value. Since this can be done only with a global variable, you need to give it a different name, for instance:

xtest(){
  typeset -g test_variable
  : ${test_variable:=$variable}
  echo $test_variable
}

This sets test_variable on the first invocation of the function, but doesn't overwrite it afterwards.

UPDATE: Changed syntax of function definition according to the comment given by Stéphane Chazelas, and also renamed my function from test to xtest, because it is a bad idea anyway to name a function 'test'.

3
  • This solution best suited my needs Thankyou!
    – Dean
    Commented Sep 25, 2018 at 0:51
  • Note that it assumes $variable is not empty upon first invocation. The typeset -g is redundant here and doesn't guard against a $test_variable potentially inherited from the environment, it would be better as unset test_variable; xtest() { ${test_variable=$variable}; echo $test_variable; } Commented Sep 26, 2018 at 6:38
  • The idea to unset is is not bad, though a careless programmer could still define it explicitly after the function definition. While the typeset -g is seemingly redundant, I use it as a habit so that the code works also if setopt warn_create_global has been used in the context where the function is defined. Commented Sep 26, 2018 at 10:42
1

First note that the function definition syntax in zsh like in the Bourne shell is:

funcname() cmd

(though it also supports the ksh syntax function funcname {...} and a few others).

fun is not a zsh syntax keyword. With fun foo() cmd, you're defining both a fun and foo function with cmd as the body.

I'd also recommend against using test as the name of a function as test is the name of a standard command (a builtin in zsh and most other Bourne-like shells).

Here if you want a function with a local variable with a fixed value, you need to embed that value in the definition of the function:

mytest() {
  local variable=test
  echo $variable
}

variable will be local to the function, but still visible to the other functions called by that mytest if any. If you'd rather want it be hidden to other functions, that is, do static scoping, you can use private (in the zsh/param/private module) instead of local.

If you want that fixed value to be the value of the $variable global variable at the time of the definition of mytest, you'll still need to embed it in the definition, something like:

zmodload zsh/param/private
eval '
  mytest() {
    private variable='${(qq)variable}'
    echo $variable
    otherfunction ...
  }
'

Where we embed the content of the variable (properly quoted with ${(qq)...}) in the definition.

4
  • I edited my post to correct syntax Thank you for pointing that out!
    – Dean
    Commented Sep 25, 2018 at 0:54
  • @StephaneChazelas : I was also surprised, when I saw this style of function definition, as I had never seen it before, but nevertheless it seems to be valid in Zsh. At least it works in Zsh 5.3. Commented Sep 25, 2018 at 8:46
  • 1
    @user1934428, but again, foo bar() cmd defines 2 functions: foo and bar, and fun bar() cmd defines two functions: fun and bar (and 'foo bar'() cmd defines a "foo bar" function). Try fun foo() uname; fun Commented Sep 25, 2018 at 8:57
  • Indeed!!!!!! Lesson learned. I will update my answer accordingly. Commented Sep 26, 2018 at 6:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .