Search code examples
unixposixzsh

encapsulate sourced script in zsh


I'm trying to control what variables get defined when sourcing a script in zsh. I'm imagining something that corresponds to this code:

(
  source variable_definitions

  somehow_export variable1=$variable_defined_in_script1
)
echo $variable1

as a result I want variable1 to be defined in the external scope and not variable_defined_in_script or any other variables in the sourced script.

(somehow_export is some magical placeholder in this example that allows exporting variable definitions to a parent shell. I believe that's not possible, so I'm looking for other solutions)


Solution

  • Something like this?

    (
      var_in_script1='Will this work?'
    
      print variable1=$var_in_script1
    ) | while read line
    do
        [[ $line == *=* ]] && typeset "$line"
    done
    
    print $variable1
    #=> Will this work?
    
    print $var_in_script1
    #=> 
    # empty; variable is only defined in the child shell
    

    This uses stdout to send information to the parent shell. Depending on your requirements, you can add text to the print statement to filter for just the variables you want (this just looks for an '=').


    If you need to handle more complex variables such as arrays, typeset -p is a great option in zsh that can help. It's also useful for simply printing the contents and types of variables.

    (
      var_local='this is only in the child process'
    
      var_str='this is a string'
    
      integer var_int=4
    
      readonly var_ro='cannot be changed'
    
      typeset -a var_ary
      var_ary[1]='idx1'
      var_ary[2]='idx2'
      var_ary[5]='idx5'
    
      typeset -A var_asc
      var_asc[lblA]='label A'
      var_asc[lblB]='label B'
    
      # generate 'typeset' commands for the variables
      # that will be sent to the parent shell:
      typeset -p var_str var_int var_ro var_ary var_asc
    
    ) | while read line
    do
        [[ $line == typeset\ * ]] && eval "$line"
    done
    
    print 'In parent:'
    typeset -p var_str var_int var_ro var_ary var_asc
    
    print
    print 'Not in parent:'
    typeset -p var_local
    

    Output:

    In parent:
    typeset var_str='this is a string'
    typeset -i var_int=4
    typeset -r var_ro='cannot be changed'
    typeset -a var_ary=( idx1 idx2 '' '' idx5 )
    typeset -A var_asc=( [lblA]='label A' [lblB]='label B' )
    
    Not in parent:
    ./tst05:typeset:33: no such variable: var_local