2

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.

  • You need a local variable so e.g. f_test(){ local var=value; print -l ${var}; } – don_crissti Sep 23 '18 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 Sep 23 '18 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 Sep 23 '18 at 11:39
  • Nope, you'll need a different language. unix.stackexchange.com/questions/94129/… – thrig Sep 23 '18 at 14:33
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'.

  • This solution best suited my needs Thankyou! – Dean Sep 25 '18 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; } – Stéphane Chazelas Sep 26 '18 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. – user1934428 Sep 26 '18 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.

  • I edited my post to correct syntax Thank you for pointing that out! – Dean Sep 25 '18 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. – user1934428 Sep 25 '18 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 – Stéphane Chazelas Sep 25 '18 at 8:57
  • Indeed!!!!!! Lesson learned. I will update my answer accordingly. – user1934428 Sep 26 '18 at 6:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.