A hiccup in my CLI installation on WSL Ubuntu

TL;DR:
Following Exercism’s CLI installation instructions created ~/.bash_profile that overrode my ~/.profile, changing the behavior of subsequent bash sessions.


Hello!

I’m on Windows 11 using Windows Subsystem for Linux to run (a fresh install of) Ubuntu-24.04. The only other thing I’d installed before Exorcism’s CLI was Ruby (…and Mise, à la the rubyonrails.org installation guide).

I followed the Linux path at the cli walkthrough so I could start working on exercises locally. As I did so,

[[ ":$PATH:" == *":$HOME/bin:"* || ":$PATH:" == *":~/bin:"* ]] && echo "~/bin is in PATH" || echo "~/bin is not in PATH"

produced “~/bin is not in the PATH”. After investigation, I think this ended up causing issues, as I then ran the next commands according to the guide, which:
–>created a ~/.bash_profile that did not exist before…
–>which made it so my ~/.profile was no longer looked at…
–>which made it so my ~/.bashrc was no longer looked at…
–>and ~/.bashrc is where my mise and ruby bash commands are initialized.

So basically, following the walkthrough seemed to break* my Ruby install by way of creating ~/.bash_profile when I shouldn’t have. (*yes, it really just broke the process that added the commands to my $PATH).

Explanation (I think):

I am not anywhere close to a Linux or Bash expert, but I have a suspicion of what’s going on here.

I did not initially have a ~/bin directory, so my running mkdir -p ~/bin according to the guide did indeed make it for me.

I see that my ~/.profile script includes

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

So that is what normally adds ~/bin to my PATH (…if it exists)! So why’d the check tell me it wasn’t there? According to the man pages, bash only auto-runs ~/.profile upon invocation of the shell.

Therefore, creating ~/bin and then immediately checking to see if it’s included in $PATH was the error of my ways (and, as it relates to my particular default setup, the error of the walkthrough’s ways). While it was not in my $PATH at that moment, a mechanism existed to where it would be added for all subsequent bash sessions. Therefore I did not need to run, and indeed should not have run:

echo 'export PATH=~/bin:$PATH' >> ~/.bash_profile
source ~/.bash_profile

That significantly* altered my bash setup–causing anything that I’d previously installed that used ~/.profile (and, subsequently, anything that used ~/.bashrc because there is code in ~/.profile to run ~/.bashrc) to no longer work as expected. (*not actually that significant… After figuring all this out, the simple, single-action fix was to just rm the ~/.bash_profile that I’d created.)

In hindsight, what I should’ve done:
After creating ~/bin, I needed to run source ~/.profile, or restart my bash session, before checking my $PATH.


Does this suggest an update to the CLI Walkthrough?

I don’t know, but I thought I’d raise the question.

I don’t know enough about Linux and bash to know why one’s system would be using ~/.bash_profile vs. ~/.profile. Or if my system’s way of adding ~/bin to the $PATH is uncommon. Or if WSL’s Ubuntu 24.04 is somehow different than non-WSL. Or really anything else (I don’t know what I don’t know). And I suspect that my exact solution would not work universally.

What I do know is that this was my experience:

  1. I installed Ruby on Rails, following the rubyonrails.org guide exactly, including a fresh/default install of Ubuntu.
  2. This seemed to be a success, and using ruby on the command line was working.
  3. I installed Exercism’s CLI, following the installation walkthrough exactly.
  4. This seemed to be a success and using excersim on the command line was working. (and see additional thought below!)
  5. I soon found that using ruby and mise on the command line were no longer working (and I actually initially second-guessed myself as to whether or not I’d installed Ruby at all! Thought maybe I’d dreamt it :face_with_spiral_eyes:)

And it seems plausible to me that others will have a similar experience. But I acknowledge that the “takeaway” to my whole episode here could just be something like, “lolz welcome to Linux–you must be new here!” I admit that I learned a decent bit that I’d guess are basics for “Linux people”.


Another thought after writing all ^that^

Thinking more about it, I probably didn’t run into ruby and mise commands not working until I was using a different bash session than the one I used to install Exercism CLI. When I started that session, ~/.profile ran and so ruby and mise were added to $PATH. Then I created ~/.bash_profile containing the command to add ~/bin to $PATH and sourced it-- so ~/bin was now also in $PATH.

Therefore, I suspect that immediately after installing Exercism CLI, everything would’ve been working as expected! But all subsequent bash sessions would be as I described above. Such latency could make this relatively minor issue maddening since it potentially leaves a user thinking “This was all working perfectly yesterday! I’ve done nothing since then! WHAT’S HAPPENING?!” (…but what they’ve “done” is closed their terminal and opened a new one)

Thanks for bringing this up. Details like this are the nightmares of support people helping beginners to get started…too many possible variations.

So first we need to add “logout and login again” after creating ~/bin. Or at least source ~/.profile. This would solve most Linux distribution cases, I think.

For those, who still do not have ~/bin in their $PATH after that: it should go into .profile if that exists, not ~/.bash_profile.

Maybe someone can point to the CLI walkthrough sources, as I did not find them on GitHub. Or do we need to involve a special maintainer for this?

I believe it’s website-copy/walkthrough/index.html at main · exercism/website-copy · GitHub. The repo seems to be open for PRs, but I’d wait until someone can confirm that.

Thanks for the link! So mkdir -p ~/bin is in one step and $PATH is in another step. That complicates things a bit more…I’d put all the changes into the latter step dealing with $PATH, then.

The check only checks for a ~/bin surrounded by :and misses it if it is at the start or end of the PATH.

The issue is has less to do with three existence of that directory and the PATH check and more to do with the complexities of which files bash reads when it starts up. See “Invocation” in the bash man page:

When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The --noprofile option may be used when the shell is started to inhibit this behavior.

When an interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc, if that file exists. This may be inhibited by using the --norc option. The --rcfile file option will force bash to read and execute commands from file instead of ~/.bashrc.

One of those is generic and the other is bash specific. Consider how users would want things to work if, for example, they swap shells once a week between bash and zsh. One could make the .bash_profile source .profile if it existed to support having both. The instructions makes assumptions about the PATH, the rc files and the shell being used. Linux has a lot of flexibility which makes it rather challenging to write instructions that apply to all users. The given instructions are relatively simple and should apply to 80-95% of users, though.

This can help reset things, but also telling people to restart everything they are running when it’s not strictly needed can be a rather cumbersome ask. The profile is part of the login process and is the best place for PATH setting, but it only kicks in on login. Should we be telling people they need to restart all their applications to have the PATH variable updated? I don’t think there’s any good answer to that. It’s one of the sharp edges of Linux that doesn’t have a great story. Ideally the best solution here is education, but telling people to go familiarize themselves with the login process of their window manager and invocation of their current (and future) shell of choice is a lot.

Restarting their season multiple times to update one variable is a lot. This is like when I call Internet customer support and they want to reboot my modem multiple times. This drives me nuts and shouldn’t be part of the setup instructions.

1 Like

My terminal re-evaluates the login files for each opening of a new window. That’s what I meant by “login/logout”. I’m too old to think about leaving my Window-Manager when hearing “re-login” :slight_smile: . In WSL it’s exit and re-opening WSL. Something along these lines. We should at least hint on that, I think.

Alas, on many Linux systems, the login files are only evaluated on login. That’s how they are technically supposed to be used. WSL may consider every terminal a new login session, but if you’re running Linux directly that’s not the case. Asking people to open a new terminal is less of an ask than telling them to restart their login session, but it wouldn’t do anything for many Linux users.

To sum it up:

  • Modify $PATH testing command to allow ~/bin as first / last part of $PATH
  • Use ~/.profile and hint on ~/.bash_profile if the former is missing (there is a hint on adjusting for shell types, a sentence like that)
  • source ~/.profile to simulate re-login, with a hint on shell specific adjustment

I’ll wait for some more opinions. I should have time for a PR the upcoming week.

Per the man page, there are three different locations bash checks for rc files. I think .bash_profile is the most commonly used file and the most correct one. The one that should be used is the one that the user is already using. The most robust thing to do is to check all three in order and use the first that exists. However, there’s a trade-off here about writing something simple that works for most people vs making sometime more complicated that would work for a few more users.

Note too that list of locations is modified by some distros/packagers so even that list won’t work every time.

The instructions already tell you to source the rc file. The problem is that the path can vary.

I did notice that that seemed to be the case, and went down that path of troubleshooting before realizing that it wasn’t the cause of my particular issue. The check told me it wasn’t there because it in indeed wasn’t there (yet).

But yes, regardless, that command needs to be checking all items, not skipping the first and last.

Yup. One easy fix for that is to test [[ :${PATH}: = *:$HOME/bin:* ]]

1 Like

I checked a lot of current Linux distributions using DistroSea and found, that RedHat-based distributions like CentOS and Fedora adhere to BASHs manual. The majority uses .profile (especially Debian/Ubuntu and others based on them like Mint) or do not have BASH installed at all :frowning_face:

I suggest to give the students a command to distinguish between these 2 major cases and ask them to copy a command version based on that output. We can adjust the sentence about “not having BASH” to those who don’t have .profile nor .bash_profile (e.g. ArchLinux or for zsh, fish et al.).

Linux is tricky because every installation can be unique and there’s an infinite number of possible setups. bash is the most common shell scripting language out there and the most commonly installed shell. It’s generally safe to assume bash is available.

I believe .bash_profile gets sourced during login for most bash users.

We could make the instructions more complex to handle more cases, either via more complicated copy paste commands or by asking users to blindly trust us to run a script we provide them. We could make them less copy paste and instead describe what users should set up, with guidance and asking them to figure out their own system. But each route has trade-offs; I don’t think there’s very much that is objectively a better choice.

Note, to make things more complicated, even if bash is installed, that doesn’t mean it’s actually being used; a system can have many shells installed but a user has a single login shell configured. That login shell is generally the only shell that matters.