$PATH issue - Cannot launch python scripts that are launched by processes like i3 and .xbindkeysrc. works with shell scripts though

So last week, on my i3 Endeavour machine, I did an update, and after rebooting, all scripts launched from i3 ( like with keyboard shortcuts) could no longer launch. Shortcuts for opening programs directly, like my browser or terminal, worked fine. I have my scripts in:

$HOME/bin 

and what I did to make them work in the first place was add that to the path in

$HOME/.profile.

Ok, so I went deeper and I found out I could add a script to /etc/profile.d/ like this:

#!/bin/bash

set_path(){

    # Check if user id is 1000 or higher
    [ "$(id -u)" -ge 1000 ] || return

    for i in "$@";
    do
        # Check if the directory exists
        [ -d "$i" ] || continue

        # Check if it is not already in your $PATH.
        echo "$PATH" | grep -Eq "(^|:)$i(:|$)" && continue

        # Then append it to $PATH and export it
        export PATH="${PATH}:$i"
    done
}

set_path ~/bin ~/scripts

Succes! I can now run shell scripts launched by i3 again. However my own python scripts are not executing, and neither are python scripts/programs installed w. pipx. Like yt-dlp.

I can run both my own python scripts and yt-dlp from terminal, but NOT from i3.

This is not specific to i3 - if I put something in .xbindkeysrc that calls a python script (with the media keys on the FN keys, for example), it does not work either.

THis is the content of echo $PATH:

/home/emil/.npm-global/bin:/home/emil/.local/bin:/home/emil/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/home/emil/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl

When I do which python I get /usr/bin/python so I can’t really figure out what the problem is here? Can you smart folks help me?

I have a hunch that this is the problem. If you log in via a display manager like lightdm (if you are indeed using a display manager), the Xsessions wrapper script will be called to start i3. And what the wrapper script does is this:

case $SHELL in
  */bash)
    [ -z "$BASH" ] && exec $SHELL --login $0 "$@"
    shopt -q login_shell || exec $SHELL --login $0 "$@"
    set +o posix
    ;;
  */zsh)
    [ -z "$ZSH_NAME" ] && exec $SHELL --login $0 "$@"
    [[ -o login ]] || exec $SHELL --login $0 "$@"
    emulate -R sh
    ;;
  */csh|*/tcsh)
    # [t]cshrc is always sourced automatically.
    # Note that sourcing csh.login after .cshrc is non-standard.
    xsess_tmp=`mktemp /tmp/xsess-env-XXXXXX`
    $SHELL -c "if (-f /etc/csh.login) source /etc/csh.login; if (-f ~/.login) source ~/.login; /bin/sh -c 'export -p' >! $xsess_tmp"
    . $xsess_tmp
    rm -f $xsess_tmp
    ;;
  */fish)
    [ -f /etc/profile ] && . /etc/profile
    [ -f $HOME/.profile ] && . $HOME/.profile
    xsess_tmp=`mktemp /tmp/xsess-env-XXXXXX`
    $SHELL --login -c "/bin/sh -c 'export -p' > $xsess_tmp"
    . $xsess_tmp
    rm -f $xsess_tmp
    ;;
  *) # Plain sh, ksh, and anything we do not know.
    [ -f /etc/profile ] && . /etc/profile
    [ -f "$HOME/.profile" ] && . "$HOME/.profile"
    ;;
esac

[ -f /etc/xprofile ] && . /etc/xprofile
[ -f /usr/local/etc/xprofile ] && . /usr/local/etc/xprofile
[ -f "$HOME/.xprofile" ] && . "$HOME/.xprofile"

The problem is, I’m not sure which user those scripts inside /etc/profile.d will be executed as. If you add this check:

# Check if user id is 1000 or higher
    [ "$(id -u)" -ge 1000 ] || return

You are assuming that the scripts will be run as the user account you’re using to login, which may not be the case.

Does it work if you remove that check?

Hey thanks for your reply!

It wasn’t the test, it’s the same now where I have commented it out. Any other ideas?

I do have lightdm installed - I didn’t do it though, it’s the one that came with the i3 EOS setup.

You have tested this after a reboot?

Something strange is happening here. This is the value of PATH when you echoed it from an interactive shell. Notice that /home/emil/bin was added twice whereas /home/emil/scripts wasn’t there at all. I don’t think set_path() did what you’d expected it to do.

set_path ~/bin ~/scripts

Is this the exact call you made in the script or is it just an example to illustrate how your script works? Or maybe the directory /home/emil/scripts didn’t exist, that’s why it was skipped?

  1. Remove the shell script you created inside /etc/profile.d
  2. Create this file instead ~/.xprofile
  3. Add the code to modify PATH into ~/.xprofile

Just skip the unecessary conditional tests and do something simple for now:

# ~/.xprofile
export PATH="${PATH}:/home/emil/bin:/home/emil/scripts"
  1. Reboot and test.

Hey sorry for the long response time, I appreciate you taking the time to help. I spend many hours figuring this out and when I solved it I had lot of normal dayjob work I had to care of.

The solution turned out to be to clean up my environment and move the PATH stuff to /etc/profile.d/ . There was some different things going on that together made it confusing, but basically what made it had to troubleshoot was that I had most of my PATH and other environment settings (like API keys ) in my $HOME/.profile, but also my .bashrc and .zshrc.

So stating this for others to find: the problem was that two weeks ago something happened in arch or EOS that changed the way the environment is created when calling stuff (bash scripts, python scripts, $EDITOR etc) from something like i3, and also when calling stuff from other scripts (like inside a bash script calling something from python).

What worked for me in the end was removing all $PATH-related stuff and putting it in the function from above, here with all (to me) relevant …/bin/ paths:


#!/bin/bash

set_path(){

    # Check if user id is 1000 or higher
    # disabled for now - might be useful in the future, could cause issues by enabling?
    # [ "$(id -u)" -ge 1000 ] || return

    for i in "$@";
    do
        # Check if the directory exists
        [ -d "$i" ] || continue

        # Check if it is not already in your $PATH.
        echo "$PATH" | grep -Eq "(^|:)$i(:|$)" && continue

        # Then append it to $PATH and export it
        export PATH="${PATH}:$i"
    done
}

# my own scripts
set_path ~/bin ~/.local/bin
# from package managers
set_path ~/.npm-global/bin ~/.cargo/bin ~/go/bin 



This took care of launcing stuff from i3 etc, and also getting python programs like yt-dlp to work (thah’ts the npm-global bin folder).

and then moving my openAI API key to an (encrypted) yaml file, since this was in the user environment, which apparently could be accessed by i3 before the update and now couldn’t. It’s probably better practice to do what I did now.

The last thing I did in order to get my EDITOR and BROWSER to work also when launching not directly by me was this:


# editor apparently set here instead, not above (at least for some stuff)
sudo cp /etc/environment /etc/environment-bak-org
sudo sed -ri 's/(BROWSER=)firefox/\1qutebrowser/g' /etc/environment
sudo sed -ri 's/(EDITOR=)nano/\1nvim/g' /etc/environment
# cat /etc/environment

so replacing firefox with qutebrowser and nano with nvim.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.