command line - ZSH: Where to place environment variable so that launched application can pick it up?

06
2014-04
  • user779159

    I need an environment variable KEY="value" made available to a GUI application before starting it. The launcher file (the one that places the icon on the desktop and sidebar in Ubuntu) has a value of Exec=/path/to/executable/file.

    When using ZSH, where should I define this variable so that it is available to that application whether I click the application launcher or whether I directly type /path/to/executable/file in my shell?

    In my command line prompt, I tried typing both KEY="value" and export KEY="value" before clicking the launcher, but it didn't seem to work. I also tried both of those lines in my ~/.zshrc, did a source ~/.zshrc from my shell then clicked the launcher again, but that also didn't work.

    Which file should it go in? I believe have a choice of ~/.zshenv, ~/.zprofile, ~/.zshrc, and ~/.zlogin.

    (For bonus points, should I use export or not?)

    (Am I required to at least log out and log back in, before the variable becomes available to the application when it's launched from the launcher?)

  • Answers
  • mpy

    As you want the variable to be defined as well in your terminal shells (interactive non-login shell) and for the desktop launcher icons (X-server started by non-interactive login shell) you should put the definition in your ~/.zshenv.

    And yes, you have to restart your x-session in order to have the new environment available for your desktop icons. Imagine such a startup scheme: Graphical Login -> Use your default shell to start the X session -> Desktop -> Shell terminal / Launch program via icon, so the child shells inherit the environment from the parent, which is used to start the X session. That shell read the RC-files only once -- on your login to the X session.

    For the bonus point. This is what the manual says:

    export [ name[=value] ... ] The specified names are marked for automatic export to the environment of subsequently executed commands. (...)

    If you define your variable in ~/.zshenv, you can in principle omit the export as this file is read in by default. The only difference arises if you start a shell with zsh -f, which sources no RC files. A little demonstration:

    % foo=foo_defined
    % export bar=bar_defined
    % print -l $foo $bar
    foo_defined
    bar_defined
    % zsh -f
    % print -l $foo $bar
    bar_defined
    % 
    

    I. e. only the exported $bar is defined in subsequent shells. But to be on the safe side, use export -- I can't think of a case where this is harmful.


  • Related Question

    Is there any command line tool that can be used to edit environment variables in Windows?
  • Piotr Dobrogost

    Is there any command line tool that can be used to edit environment variables in Windows?

    It would be nice if this was smart tool, for example:

    • When adding some path to let's say the PATH variable and this path is already there it shouldn't double this entry.
    • Inserting a new path to the PATH variable should be possible before/after some other path or in specific order (the first, the 7th, the last etc.).
    • It should be possible to change only part of variable's value (in case of the PATH a given path from a list of all paths).

    And the last but not the least - I want my changes to persist between sessions so simple SET is out of question...

    There's very nice GUI tool for this called Path Editor and I need something like this but for command line.


  • Related Answers
  • Treb

    I don't know any tool that does this, but maybe you can use the regcommand:

    reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path
    

    to read the current path, and

    reg add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /d "newPath" /f
    

    to write your new value.

    You need admin rights for hsving right acccess in HKLM. If that is a problem, consider modifying the user specific path setting in HKCU\Environment instead.

  • bobbymcr

    If you need a generic way to set any environment variable and have the changes persist, then setx.exe would be the tool to use. It cannot do the "smart" things you are asking for, though...

    setx.exe is included with Windows Vista or later; if you use an earlier version of Windows, you can use the above download link to get it.

  • Joey

    For the current program, there is path:

    Displays or sets a search path for executable files.

    PATH [[drive:]path[;...][;%PATH%]
    PATH ;
    

    Type PATH ; to clear all search-path settings and direct cmd.exe to search only in the current directory.

    Type PATH without parameters to display the current path. Including %PATH% in the new path setting causes the old path to be appended to the new setting.

    However, this is pretty much the same as set PATH.

    For environment variables to persist you have to edit the registry or use setx.

  • Indrek

    I just discovered the ability to allow the users to run the Environment Variables edit dialog without elevated privileges.

    From the Start menu, run the following:

    rundll32 sysdm.cpl,EditEnvironmentVariables
    
  • sangretu

    set PATH

    (help set)

  • Cheeso

    I wrote a set of batch scripts for this. addpath.bat adds elements to the path, rmpath.bat removes elements from the path, and lpath.bat just lists the path. But then I needed some support scripts, so there is also chkpath.bat .

    It ended up being not trivial and required tr.exe and cat.exe, a couple of unix-style utilities. The reason its not trivial: no backticks in cmd.exe (though you can use for loops for this), and short names versus long names.

    addpath.bat:

    @echo off
    setlocal
    set cwd=%~dps0
    
    goto testit
    
    :loopy
    
    call %cwd%chkpath "%~1"
    if %errorlevel%==2 (
      set path=%path%;%~1
    )
    
    shift
    
    :testit
    if not _%1==_ goto loopy
    
    
    call %cwd%lpath.bat
    
    endlocal & set path=%path%
    

    ChkPath.bat:

    @echo off
    goto START
    
    -------------------------------------------------------
    chkpath.bat
    
    checks path for existence of the given segment.
    Returns 1 if present, 2 if not present, 0 if not checked.
    
    The matching and checking complicated by case sensitivity and "short pathnames".
    
    created sometime in 2003 and lovingly maintained since then.
    
    
    -------------------------------------------------------
    
    :START
    setlocal enabledelayedExpansion
    set rc=0
    set cwd=%~dps0
    set curdrive=%~d0
    set tr=%curdrive%\bin\tr.exe
    set regexe=%windir%\system32\reg.exe
    
    
    if _%1==_ goto Usage
    
    
    @REM convert arg 1 to a fully-qualified, short path name,
    @REM and then convert to uppercase.
    set toupper=%~fs1
    call :ToUpper
    set tocheck=%toupper%
    
    
    if not _%TEMP%==_ goto GotTemp
    call :gettemp
    
    
    :GotTemp
    set d=%DATE:~4%
    set stamp=%d:~6%%d:~3,2%%d:~0,2%%TIME::=%
    set d=
    set tempfile1=%TEMP%\chkpath1-%stamp%.tmp
    
    echo %path% | %tr% ; \n  >  %tempfile1%
    
    @REM check each element in the path for the match:
    for /f  "delims=^" %%I in (%tempfile1%) do (
      if !rc!==0 (
    call :CheckElt "%%I"
      )
    )
    
    if %rc%==0 set rc=2
    goto END
    
    
    --------------------------------------------
    * checkelt
    *
    * check one element in the path to see if it is the same
    * as the TOCHECK string. The element is first canonicalized.
    *
    
    :CheckElt
    @REM remove surrounding quotes
    set ERF=%1
    if [x%ERF%]==[x] goto CheckEltDone
    @REM convert to fully-qualified, short paths, uppercase
    set TOUPPER=%~fs1%
    call :ToUpper
    if _%TOCHECK% == _%TOUPPER% set rc=1
    :CheckEltDone
    goto:EOF
    --------------------------------------------
    
    
    --------------------------------------------
    * backtick
    *
    * invoke a command and return the result as a string.
    * This is like backtick in csh or bash.
    * To call, set variable BACKTICK to the command to be run.
    * The result will be stored in the env variable of the same name.
    *
    
    :backtick
    FOR /F "usebackq delims=" %%i IN (`%backtick%`) DO (
      SET backtick=%%i
    )
    goto backtick_done
    :backtick_none
      SET backtick=nothing to exec
    :backtick_done
    goto:EOF
    --------------------------------------------
    
    
    --------------------------------------------
    * gettemp
    *
    * get the temporary directory, as stored in the registry.
    * Relies on backtick.
    *
    * The result set TEMP.
    *
    
    :gettemp
    set regkey=HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
    set regvalname=Local AppData
    set backtick=%regexe% query "%regkey%" /v "%regvalname%"
    call :backtick
    for /f "tokens=4" %%a in ("%backtick%") do (
      set temp=%%a
    )
    goto:EOF
    --------------------------------------------
    
    
    
    --------------------------------------------
    * ToUpper
    *
    * Convert a string to all uppercase.
    * To call, set variable TOUPPER to the thing to be converted.
    * The result will be stored in the env variable of the same name.
    *
    
    :ToUpper
      FOR /F "usebackq delims=" %%I IN (`echo %toupper% ^| %tr% a-z A-Z`) DO (
    SET toupper=%%I
      )
    goto:EOF
    --------------------------------------------
    
    
    --------------------------------------------
    :CleanUp
      if _%tempfile1%==_ goto CleanUpDone
      if exist %tempfile1% del %tempfile1%
      :CleanUpDone
    goto:EOF
    --------------------------------------------
    
    
    --------------------------------------------
    :Usage
    echo.
    echo Usage: chkpath ^<path^>
    echo checks if path element is included in path variable.
    echo returns 1 if yes, 2 if no, 0 if not checked.
    echo.
    goto END
    --------------------------------------------
    
    
    :END
    call :CleanUp
    
    :ReallyEnd
    
    endlocal & set errorlevel=%rc%
    @REM set errorlevel=%rc%
    @REM echo %errorlevel%
    

    lpath.bat:

    @echo.
    @set curdrive=%~d0
    
    @REM This form post-fixes a | at the end of each path element. Useful for debugging trailing spaces.
    @REM @path | %curdrive%\cygwin\bin\sed.exe -e s/PATH=// -e 's/;/^|\n/g' -e 's/$/^|/g'
    
    @REM This form shows bare path elements.
    @REM @path | %curdrive%\cygwin\bin\sed.exe -e 's/PATH=//' -e 's/;/^\n/g'
    @path | %curdrive%\utils\sed -e "s/PATH=//" | %curdrive%\utils\tr ; \n
    @echo.
    
  • hugo der hungrige

    You might wanna check out pathed of the gtools collection: http://www.p-nand-q.com/gtools.html

    It provides a set of commands for the command promt like

    pathed /APPEND %CD% /USER
    

    to append the current path for example. I haven't really checked it out to be honest, as I'm totally fine with using a GUI.

    Other options are:

      /MACHINE: print machine PATH
         /USER: print user PATH
          /ADD: add variable at the head
       /APPEND: add variable at the tail
       /REMOVE: remove path / index
         /SLIM: strip duplicate vars
          /ENV: environment variable, defaults to PATH
    

    Together with which of the same collection, you got yourself some good tools, I suppose. Which "locates executable files on the PATH".

     /EXTENSION: search for extension , can be a ; separated list
           /DIR: add directory , can be a ; separated list
     /RECURSIVE: search directories recursively
        /SINGLE: stop after the first find result
           /ENV: environment variable, defaults to PATH
    FILE {FILE}: one or more files to find
    

    Source: http://op111.net/82/

  • Piotr Dobrogost

    Path Manager (pathman.exe) from Windows Server 2003 Resource Kit Tools is the closest match I could find. It was already available in NT Resource Kit.

  • matt wilkie

    How to check if directory exists in %PATH%? on Stack Overflow has an outstanding description of what makes Windows PATH editing difficult along with a batch file to overcome them. Figuring out how to properly use addpath.bat took a bit of practice as it's calling structure was new to me, but this works:

    set _path=C:\new\directory\to\add\to\path
    call addpath.bat _path
    set _path=
    

    and repeated firings won't add the new directory if it's already present. This doesn't address making the edits persistent across sessions.