#script #interpreter #target #sway #parser #shim #printenv #user-defined

app envshim

Symlink shim to load executables with user-defined environment variables

2 unstable releases

0.2.0 Oct 11, 2023
0.1.0 Aug 31, 2023

#80 in Configuration


163 lines


EnvShim is a symlink shim to load executables with user-defined environment variables. Refer next section for more details on what this means.

Status: This project is active and a 1.0 release is planned. It currently has all the features I personally expect from it and is of beta quality. However, it will be in 0.x version for a while to identify any bugs or essentially needed features. Not a lot of features will be added, since that may slow down program and delay the loading of the final application.

EnvShim in detail

The problem: A big issue on a GNU/Linux desktop is that there are so many incompatible ways to define environment variables. A cursory search indicates /etc/profile.d/, .bashrc, ~/.profile, ~/.xprofile, ~/.config/environment.d/envvars.conf, /etc/environment and numerous other locations. There is no reliable method to define all the variables in one place and have all the applications pick them up. There are also surprising ways in which desktop managers like SDDM and GDM process these variables. Some desktop environments like Gnome and KDE force a standard way of defining users' environment variables. However, it's still an issue on window managers like sway or awesome.

The solution: EnvShim aims to provide a way for users to define their variables in a single source of truth (~/.config/envshim/script file) and ensure that the desired applications pick it up.

The way EnvShim solves this is by acting as a loader shim for the desired target applications. For this, symlinks to the envshim executable is with the same name as the target application is placed in directory that has precedence over the actual target application in the $PATH variable. Consider an example using the sway executable:

_# printenv PATH

_# which sway

_# which envshim

_# ln -sr /usr/local/bin/envshim /usr/local/bin/sway

_# rehash

_# which sway

In the above case, /usr/local/bin has a higher precedence than /usr/bin. Therefore, when we try to execute sway, envshim will be invoked via the symlink in /usr/local/bin instead of /usr/bin/sway. Envshim then takes care of initializing the variables and then invoking the target (/usr/bin/sway).

User settings: The second requirement for this to work is a file where the variables are declared. This has to created by the user in their home directory under $XDG_CONFIG_HOME/envshim/script. If $XDG_CONFIG_HOME is undefined, the default location is assumed - ~/.config/envshim/script.

The script file is a shell script written for a shell (like sh or bash) of user's choice. At the time of shim loading, envshim invokes that shell as a subprocess and feeds the content of the script to it. Envshim then reads the result of the script execution and uses it to define the environment for the target application. Envshim then execs into the target application, replacing itself with the target application in the process.


Clone this repository and cd into it. Then issue the normal cargo command to build it. Copy the executable to the desired location afterwards.

git clone https://git.sr.ht/~gokuldas/envshim
cd envshim
cargo build --release
sudo cp target/release/envshim /usr/local/bin


There are two steps in the configuration process:

1. Script file: The user has to create a script file at $XDG_CONFIG_HOME/envshim/script. It doesn't need an executable permission. The first line is a shebang line indicating the shell to use and configured to accept input from stdin. The following are some options:

  • #!/usr/bin/sh -s
  • #!/usr/bin/bash -s
  • #!/usr/bin/zsh -s

Fill the script file to print the necessary variables in a VAR=value format, one variable per line. This can be done using echo, for example. If it's desired to print out all the environment variables at once, printenv command does the job. Just remember to export the variables before using printenv. For example:

export PATH=$HOME/.local/bin:$PATH


echo 'ENVSHIM_MARKER=envshim'

A sample of this file is provided as assets/script in this repo.

2. Create shims: Shims are symlinks with the same name as the target and pointing to envshim executable. The important matter here is to ensure that the shims come first in $PATH before the target executable. For example, if PATH=/usr/local/bin:/usr/bin and the target application is /usr/bin/sway, then /usr/local/bin/sway is reasonable choice for the shim. Another matter to note is that PATH variable mentioned here is what you get before shim loading. Don't depend on paths defined in the script file. Have a look at the example given in 'EnvShim in detail' section.

Which applications should be chosen for shim loading? There are two guidelines that can help decide.

  1. Any application for which you want to ensure the correct variables
  2. Any application that is the parent process of most other applications

Shim loading adds a delay time to the loading of the target application, since a shell has to be run before it. The second guideline helps to reduce such delays by doing shim loading fewer times and then passing on the result to as many other processes as possible. Here are some possible candidate for shim loading:

  • Shells (like bash or zsh)
  • Window managers (like sway or awesome)


Envshim is designed to run the target application in any of the cases where the target is available. This means that the target will run even if the shell or the script fails or is missing. However, the environment variables that the target receives may not be what you expect. It's designed like this to avoid making the target application inaccessible in case of any other error. You wouldn't want your shell or window manager to be inaccessible because of a missing or misconfigured script.

If you suspect such a fail-safe shim load, you should try running the application from a command shell. EnvShell prints error messages on stderr if it encounters any problem.


Suggestions and contributions are welcome through the mailing list. Refer to the Contributor Guidelines and Project Policies page of my free software index for details on how to contribute. Meanwhile, the following additional guidelines apply:

  1. Format your code with rustfmt before submission
    • The text width for markdown documents is 100
  2. The patches must be signed-off (git commit -s)
  3. Set up the cloned local repository with the following configuration:
git config format.to "~gokuldas/projects@lists.sr.ht"
git config format.subjectPrefix "PATCH EnvShim"
git config format.coverLetter auto
git config format.useAutoBase true
git config format.signOff true


envshim: Symlink shim to load executables with user-defined environment variables
Copyright (C) 2023 Gokul Das B
SPDX-License-Identifier: GPL-3.0-or-later

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.


~178K SLoC