Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

Populate tcsh environment variables via a script UNIX
I have a G4 Cube (running Panther) that I use for serving web pages, hosting a CVS repository and for a few other things. Fairly often I need to log into this machine over SSH to perform some remote administration.

The problem is I followed this tip from Apple to load environment variables (like CVSROOT and CVS_RSH) into the GUI environment using ~/.MacOSX/environment.plist. So, if I log in remotely using SSH, those environment variables aren't set in my shell environment. While I could just duplicate the setting of these environment variables in ~/.tcshrc (or ~/Library/init/tcsh/environment.mine if you followed this hint), as a programmer I know that duplication of data is the root of all evil :-).

I've wanted to learn Ruby, so I decided to whip together a little script to parse ~/.MacOSX/environment.plist and load the variables into the tcsh environment. Save this script in a file called parseEnvironmentPlist.rb in your ~/bin directory:
#!/usr/bin/ruby

#
# A script for parsing ~/.MacOSX/environment.plist and loading the 
# environment variables it defines into a tcsh environment.
#

# a regex for matching <key>...</key> lines
# group 1 is the name of the key
key_re = /^\s*<key>([A-Za-z]+[_A-Za-z0-9]*)<\/key>\s*$/

# a regex for matching <string>...</string> value lines
# group 1 is the value of the environment variable
value_re = /^\s*<string>([-_:.\/0-9A-Za-z]+)<\/string>\s*$/

File.open("#{ENV['HOME']}/.MacOSX/environment.plist", "r") do |plist|

 currentKey = "" # the key we're currently processing
 
 # look at each line of the file to find keys
 # followed by values
 plist.each_line do |next_line| 
  
  # if we find a key, hold on to it 
  if key_re =~ next_line
   currentKey = $1
   currentValue = ""
  
  # since key lines alternate with value lines,
  # if we match a value line, we know it's a value
  # for the previously matched key
  elsif value_re =~ next_line
   currentValue = $1
   
   # output a setenv command to stdout that's 
   # suitable for running through tcsh's eval
   puts "setenv #{currentKey} #{currentValue};"
   
   currentKey = currentValue = ""
  end
  
 end

end
Make the script executable (execute chmod 750 ~/bin/parseEnvironmentPlist.rb in Terminal) and add the following line to your ~/.tcshrc (or ~/Library/init/tcsh/rc.mine if you've followed this hint):
eval `~/bin/parseEnvironmentPlist.rb`
Note that those are backticks in the above command, NOT single quotes! Now you can keep all your environment variable definitions in a single location (~/.MacOSX/environment.plist) and still use them when you log in remotely!
    •    
  • Currently 2.80 / 5
  You rated: 5 / 5 (5 votes cast)
 
[18,418 views]  

Populate tcsh environment variables via a script | 10 comments | Create New Account
Click here to return to the 'Populate tcsh environment variables via a script' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Populate tcsh environment variables via a script
Authored by: wgscott on Apr 01, '04 11:49:36AM

Wouldn't it be easier to put a one line command in the foo.plist file and have that command be one to source the environment file for tcsh (or zsh or bash)?



[ Reply to This | # ]
Populate tcsh environment variables via a script
Authored by: Iowa Boy on Apr 01, '04 12:29:17PM

I believe you would have it backwards then. The .plist isn't actually read when you ssh into a machine. The script that he wrote is executed when the standard .tcshrc is loaded.



[ Reply to This | # ]
Populate tcsh environment variables via a script
Authored by: wgscott on Apr 05, '04 09:28:32AM

Right, but if you put the environment variables in the standard file, eg, .cshrc, and then you use the plist file to read THAT file whenever the plist file is run, it covers both types of logins.

In other words, do as you normally do, but just set the plist file to read the same variables.



[ Reply to This | # ]
Populate tcsh environment variables via a script
Authored by: jrdodds on Apr 19, '04 08:41:38PM

How would you do that? What would you put in the plist file that would cause another file to be read?



[ Reply to This | # ]
Populate tcsh environment variables via a script
Authored by: kholburn on Apr 01, '04 05:11:19PM
You only need this script when you log in remotely. When you log in locally you don't need it. If I knew any ruby I could add a test for the whether the first environment variable was already defined and terminate.

maybe:

if #{ENV[currentKey]} !~ /^$/
 exit
end


Maybe someone who knows ruby could do better


[ Reply to This | # ]
Populate tcsh environment variables via a script
Authored by: ssantry on Apr 02, '04 11:17:59AM

I think running this script only for remote logins is a good idea, but it's the shell's responsibility to determine this, not the script's.

Putting the following in ~/Library/init/tcsh/rc.mine (or ~/.tcshrc) worked for me:


if ($?SSH_CLIENT) then
    eval `~/Applications/bin/parseEnvironmentPlist.rb`
endif

---
- Sean

[ Reply to This | # ]

New Version for both Bash and Tcsh
Authored by: ssantry on Apr 02, '04 11:47:55AM

I figured since Panther defaults to bash, I should modify the script to support bash as well, so here it is. Usage is pretty much the same, except you run this script from ~/.bashrc instead of ~/.tcshrc.


#!/usr/bin/ruby

#
# A script for parsing ~/.MacOSX/environment.plist and loading the 
# environment variables it defines into a shell environment.
#

# determine which shell the user is running
# currently we support bash and tcsh
# since bash is the default shell on Panther, 
# we'll default to that here as well
if /^\/[-A-Za-z\/]+\/(bash|tcsh)$/ =~ ENV['SHELL']
    shell = $1
else
    # if we can't determine the users shell, or if
    # it's an unsupported shell, bail out here
    exit 1
end

# a regex for matching <key>...</key> lines
# group 1 is the name of the key
key_re = /^\s*<key>([A-Za-z]+[_A-Za-z0-9]*)<\/key>\s*$/

# a regex for matching <string>...</string> value lines
# group 1 is the value of the environment variable
value_re = /^\s*<string>([-_:.\/0-9A-Za-z]+)<\/string>\s*$/

File.open("#{ENV['HOME']}/.MacOSX/environment.plist", "r") do |plist|

    currentKey = "" # the key we're currently processing
    
    # look at each line of the file to find keys
    # followed by values
    plist.each_line do |next_line| 
    
        # if we find a key, hold on to it 
        if key_re =~ next_line
            currentKey = $1
            currentValue = ""
        
        # since key lines alternate with value lines,
        # if we match a value line, we know it's a value
        # for the previously matched key
        elsif value_re =~ next_line
            currentValue = $1
        
            if shell == "bash"
                # output a setenv command to stdout that's 
                # suitable for running through bash's eval
                puts "#{currentKey}=#{currentValue}; export #{currentKey};"
            elsif shell == "tcsh"
                # output a setenv command to stdout that's 
                # suitable for running through tcsh's eval
                puts "setenv #{currentKey} #{currentValue};"
            else
                # we should never get to this point since we 
                # exit much earlier if the shell type can't be 
                # determined. But, just in case, exit here too.
                exit 1
            end
        
            currentKey = currentValue = ""
        end
    
    end

end

---
- Sean

[ Reply to This | # ]

New Version for both Bash and Tcsh
Authored by: ssantry on Apr 02, '04 11:54:58AM

Err, ignore that comment on lines 10 and 11 of the new script. If the script can't determine the shell, it exits right away and doesn't default to bash...



[ Reply to This | # ]
New Version for both Bash and Tcsh
Authored by: Thomas Kaiser on Apr 03, '04 11:46:36AM
Hey folks,

Apple provided us with the "defaults" command to deal with property lists.
So, to read all key/value pairs in a very simple and effective way, you simply need

     defaults read "${HOME}/.MacOSX/environment"

That said, the bash way suitable for 99 percent of all cases to include directly into .bashrc would read as follows (on a single line): defaults read "${HOME}/.MacOSX/environment" | tr -d "{" | tr -d "}" | sed 's{\ =\ {={g' | tr ";" "\n" | grep "=" | while read -r OneLine; do eval export $OneLine; done

Cheers,

Thomas

[ Reply to This | # ]
New Version for both Bash and Tcsh
Authored by: Thomas Kaiser on Apr 03, '04 12:29:47PM
Two small additions:

> the bash way suitable for 99 percent of all cases

That means, this will work unless key or value contain "{", "}", or ";" because they will be converted while parsing the property list.

> tr ";" "n"

Should read "\n". The backslash character "\" has been eaten by the form submission, so once again:
defaults read "${HOME}/.MacOSX/environment" | tr -d "{" | tr -d "}" | sed 's{ = {={g' | tr ";" "\n" | grep "=" | while read -r OneLine; do eval export $OneLine; done


[ Reply to This | # ]