Ask HN: Better Solution Than $Path

5 points by h_tbob ↗ HN
Hello fellow friends!

I may be a little crazy, but I'm upset that we still have to dink with $PATH.

Doesn't it make sense to have a little database, even if it's just a flat file that contains the name of an executable, the available places it can be found, and the default?

This would save so much time. Think about it. Whenever you install a program, you automatically call `linpath link /usr/opt/program/bin/executable`

Then the "linpath" binary links the executable to the PATH. Or if you pass a directory, then it would add all entries in the directory to the database.

I'm not an expert at C and have never compiled linux. But this has got to be the easiest thing in the world to make for somebody who's smart. I just can't understand, how in the world has this not been done. I just think it's crazy we are still recursing through directories to find binaries. It's just so annoying every time I install anything, even if through homebrew, trying to get stuff on the PATH, cause I never know where it is!

I think we should do this for LD_LIBRARY_PATH and other cool stuff like this too.

So if I want to make this, here was my idea. I will make a flat file like this:

binary_name, path1:path2:path3

Then in order to add something to it, the program will call

``` linpath add /path/to/executable or /path/to/dir ```

then linpath will do 2 things. First, it will read the config file and add any to the path (at the end by default). if you do it in interactive mode, it may prompt you if there are conflicts to see what is default. The first one in the list would be the default one.

To make this simple, linpath will symlink the default ones to /usr/bin/linpath/ or something like that, and when linpath runs, it symlinks or hard links or whatever to that dir.

This might cause a little problem since the binaries may need to talk to their neighbors, so instead of symlinking to /usr/bin/linpath, it does `cd /path/to/executable/dir` and then runs it.

This is a incomplete solution, but this, in my opinion, would make life much better for all. What are your thoughts?

Please be kind, I'm a noob at C++ sometimes, and just don't understand linux that great, cause I haven't really worked on the source code. I've done a lot of frontend stuff, but never had a chance to dive into C++ for some reason. So if you are an expert, take it from a n00b that this stuff is complicated for us and we would like to help, I just don't know where to start. SO if you have ideas, please tell me, and I might be able to build it. Then we would have to integrate it into homebrew if it worked or something.

28 comments

[ 3.8 ms ] story [ 75.7 ms ] thread
Why is the database easier to work with than just looking at $PATH and either putting your executable in an existing directory or adding a new directory?
I think that there should be a database so that any time I install a program, the program will update the database so I never have to look for the program. Also the database would allow me to set the default and I could change it doing: `linpath default python3` and it would give a menu to select the default. Don't you think that would be great?

I just think this would make installation so easy!

There is such a database: it's the filesystem. The system package manager puts executables into /usr/bin and friends. Homebrew on Macs defaults to /usr/local/bin.

> Don't you think that would be great?

No. It's still not clear to me what this layer you're proposing would solve, relative to the current state. Other than that now every program would have to think about this new abstraction.

As somebody pointed out in a parallel comment, you can approximate exactly what you're trying to pitch without writing any C: just set "export PATH=~/.linpath", and then write some helpers to manage the contents of that directory. I think if you tried to build a system like this you'd start to realize that you're reinventing what PATH already enables, with a lot more custom glue.

Why does that upset you? Many shells build a hash table of command locations (in bash or zsh, see the hash builtin command. while you're at it, also check out the which command) so they don't need to go "recursing through directories" more than once.

I've dealt with systems where you need to update a file with a list of executables and their location. Having the shell handle that automatically is better.

It upsets me because it's so basic. Doesn't it seem like we should have a better system by now?

Specifically when I install multiple versions of a library, or install a new library that I don't know, I don't want to dink with the path. I don't see any reason I should have to run this command `export PATH="/path/to/executable:$PATH`. I think that this is bad for 3 reasons:

1. It's error prone because you can easily make typos 2. You have to dink with it to switch which executable you want 3. This is such an insanely common task, it seems ludicrous that we haven't come up with a simple command to register executables!

How is this an insanely common task? I literally never have to dink with $PATH on Linux, and only rarely on Mac because homewbrew has decided that certain executables shouldn’t be linked in by default.

I think the reason you are getting pushback is that you’ve proposed a complex replacement to a simple existing solution which basically just isn’t a problem. Most developers become allergic to complexity over time, hence the response.

It sounds like your actual problem is with the homebrew project, not with $PATH.

(comment deleted)
I think you're correct that $PATH works. But I just think it makes more sense to have a more developed solution, that's all.

I thought up another thing wrong with path. I think path should be configurable to search relative paths as well. So I could configure it so that it always searched node_modules/bin for executables as well. What do you think?

You could create your own bin directory in your user directory (~/bin) and add it to your PATH.

Then you can create symlinks in ~/bin to whatever executables you want using whatever names you prefer.

If you have programs that need to run from a given location, you could create little launcher scripts that cd to the location and run the executable.

The PATH environment variable has worked the way it does since the 1970s and everything expects it to work that way. Since it is all text, it should not be too difficult to find or build tools to manage it or other environment variables.

So the history is awesome. But that's kind of the problem. Times change, and I think it would be so nice to just have a simple utility that whenever someone installs a package, it automatically registers all executables, you know?

Do you ever get frustrated when you install a library or something and can't seem to figure out where the executable is, cause you installed it with brew or something?

To me the real benefit is when people install a program, that they instantly get access without having to update their path manually! Plus by default the installation wouldn't override the existing items because they would just go second or third in line in the database.

I'm surprised more people don't think this would be a good idea. I honestly thought it would make all our lives so easy, not having to dink with path.

Honestly, do you find PATH frustrating? Or am I the only one?

>Times change, and I think it would be so nice to just have a simple utility that whenever someone installs a package, it automatically registers all executables, you know?

So ... have the installer (whatever that may be (rpm, flatpack, snap, the admin extracting a tarball...) add an entry to $PATH like this:

`export PATH = $PATH:/new/path/to/add/for/new/executables`

Ok think this through. I have to edit a variable by appending to a string. That makes no sense! I should have a simple command to prevent syntax errors!

More importantly, how do you ensure that you can easily access the new one? For example lets say I am installing python. How do I easily set the python3 binary? With the system I propose, you simply run

linpath info python3

>>>output

/usr/bin/python3

/opt/homebrew/python3.10/etc/bin/python3

/opt/homebrew/python3.11/etc/bin/python3

This would tell me exactly which python3 executable I'm using, but also it would also allow me to set my favorite one:

linpath select python3 ... shows a dialog where i can choose 1,2,3 etc.

The nicest thing about this that you can't emulate with PATH is this: How do you have a simple list of all know locations of this binary? This would be so freaking useful when running multiple versions of "node" for example.

You know what? I was thinking that we could also do this for compatibility:

linpath search

Then what it would do is search for all binaries on the system (i.e. executable files), and create it's own database. Then it could have a flag in the database that certain ones are not "registered", but when you try to run them, it echos "this command is available at /path/to/executable" but hasn't been linked. To link run `linpath activate binary_name`.

Lastly, how is the installer to know where to update the PATH? .zshrc, .bash_profile, the systemwide one... So hard to understand!

So probably the linpath should have a systemwide database, and a user specific database as well maybe.

I'm not trying to argue, I just see so many shortcomings to PATH, specifically, the installer never knows what file to update, and it's not even available in cron jobs either. This can be remedied, but not without trouble! I think linux is great, but it's such a nerdy platform, I want to make it easier.

>Ok think this through. I have to edit a variable by appending to a string. That makes no sense! I should have a simple command to prevent syntax errors!

"That makes no sense"

Except ... it does

and it has for over half a century

>Then what it would do is search for all binaries on the system (i.e. executable files), and create it's own database. Then it could have a flag in the database that certain ones are not "registered", but when you try to run them, it echos "this command is available at /path/to/executable" but hasn't been linked. To link run `linpath activate binary_name`.

You ... just described updatedb and locate

Don't want to use the binary in $PATH? Give the full path to the one you want

>I'm not trying to argue

Except ... you are - what you're describing just is not efficient

Maybe you've grown accustomed to the Windows Registry - are you also familiar with all the problems it has (vs the rock-solid, impossible to break environment variable)?

>I just see so many shortcomings to PATH, specifically, the installer never knows what file to update, and it's not even available in cron jobs either.

Of course an install can "know what file to update" - because it's not a file! It can put (if appropriate) a symlink to the executable into a normal location used by $PATH, or it can create its own environment variables for when it runs

Or - as a last resort - it could update $PATH (a generally-bad idea, but still possible)

Regarding the registry, I was under the impression you have to update the PATH on windows as well. I have tried dinking with it, and without updating the path, the command line can't find the proper programs. Am I missing something?
Some commandline tools references the registry

Some do not

Ld_library_path is an runtime override for the normal library paths defined in the ld.so.conf. in 99% you don't need to override libraries with it. If you compile an program for /opt then its common to use rpath or putting the libraries in the directories defined in the FHS
(comment deleted)
>I just think it's crazy we are still recursing through directories to find binaries

Except ... we are not

$PATH does not "recurse" - it gives a set of prefixes the system will attempt before a command before failing (unless, of course, you just give the whole path, like `./my-cmd` or `/path/to/my-cmd`)

>So if I want to make this, here was my idea. I will make a flat file like this:

>binary_name, path1:path2:path3

Holy path, Batman!

Now you have to manage for each and every possible executable ALL the places it might exist?

Let's say you have 100 executables in /bin

You now need (just to reference those 100 commands) a 100-line 'flat file' that looks like:

#######

ls, /bin ln, /bin mkdir, /bin

#######

OR you could just do what has been done for 50+ years, and use $PATH which looks like this:

`export PATH = /bin:/usr/bin...`

One easy-to-update line ... or HUNDREDS of hard-to-update lines?

(comment deleted)
> ... so instead of symlinking to /usr/bin/linpath, it does `cd /path/to/executable/dir` and then runs it.

Oh hell no. Think about what happens if you run "ls".

Ok fine. Good point. Maybe what it does instead is manage the PATH variable itself so that it doesn't mess anything up. What do you think?
I guess if it's a symlink, then, that would pretty much solve all the problems, wouldn't it?