Maybe you need an env var for something you're doing in lisp or for some library. How can you set it?

I usually export my env vars from .bashrc, especially if they don't require extra caution, for example, any token you use for running a bot. So, we go in .bashrc and write:


To get the value in Emacs, you should be able to launch getenv like this

(getenv "VARNAME")

But it's not so simple. Are you surprised? I don't think so, it's never so simple.

Why your getenv function is giving you a nil, instead of your craved string? Maybe you aren't running Emacs from within the shell. That's my case because I run the Emacs daemon from systemd. I think my option could be to launch the daemon from the shell, but I would like to maintain my current approach to the daemon.

I found that xahlee covered this topic in a post of his and he basically said that you could actually launch envvars from within emacs itself as a solution. It feels hacky to me. The other solutions are specifically for Windows or MacOS, so I moved over and thought about exposing the env vars from systemd.

A member of the Arch community "found a good way to export environment variables using systemctl so that they are available to systemd spawned processes". This could be exactly what I was looking for, but I don't like to mess with systemd, because I found .bashrc more comfortable, so I kept looking for a solution with the actual approach. I keep this here as plan B.

So I found this interesting answer on unix.stackexchange which linked a gist which presents a

nice piece of Emacs lisp that uses diff to compare outputs of export command before and after sourcing, and then calls setenv function accordingly.

let's see it:

(defun source (filename)
  "Update environment variables from a shell source file."
  (interactive "fSource file: ")

  (message "Sourcing environment from `%s'..." filename)

    (shell-command (format "diff -u <(true; export) <(source %s; export)" filename) '(4))

    (let ((envvar-re "declare -x \\([^=]+\\)=\\(.*\\)$"))
      ;; Remove environment variables
      (while (search-forward-regexp (concat "^-" envvar-re) nil t)
        (let ((var (match-string 1)))
          (message "%s" (prin1-to-string `(setenv ,var nil)))
          (setenv var nil)))

      ;; Update environment variables
      (goto-char (point-min))
      (while (search-forward-regexp (concat "^+" envvar-re) nil t)
        (let ((var (match-string 1))
              (value (read (match-string 2))))
          (message "%s" (prin1-to-string `(setenv ,var ,value)))
          (setenv var value)))))
  (message "Sourcing environment from `%s'... done." filename))

It looks like a good solution: one could add this to the config file followed by a

(source ".bashrc")

and getting your exports now and forever without problems. Right? Well, it doesn't work for me.

Now I must do other things in my life, but I promise that I will update this post soon, hopefully with a reasonable and elegant solution. Better: with a working solution. A working solution would be just fine.