Settings

Theme

Show HN: Justpath – a simple utility to explore the PATH environment variable

github.com

76 points by epogrebnyak 2 years ago · 28 comments

Reader

arp242 2 years ago

For zsh I use this to setup $PATH, which seems to address most of the use cases of this tool:

  ### Setup PATH
  dirs=(
      /usr/lib/ccache/bin                   # ccache
      ~/.local/script ~/.local/bin          # My local scripts.
      ~/.local/gobin                        # GOBIN
      /usr/local/bin /usr/local/sbin        # local takes precedence
      /bin /sbin /usr/bin /usr/sbin         # Standard Unix
      /usr/pkg/bin   /usr/pkg/sbin          # NetBSD
      /usr/X11R6/bin /usr/X11R6/sbin        # OpenBSD
      /opt/ooce/bin                         # illumos
      ~/.local/share/gem/ruby/*/bin(N[-1])  # Ruby
      ~/.luarocks/bin(N[-1])                # Lua
      ~/.local/dotnet/root ~/.local/dotnet/tools  # .NET
      /usr/lib/plan9/bin                    # Plan 9 from userspace
      ~/code/Vim/gopher.vim/tools/bin       # gopher.vim
      ~/.nimble/bin                         # Nim
      ~/.cargo/bin                          # Rust
      ~/.ghcup/bin                          # Haskell
  )
  typeset -U path=()                        # No duplicates
  # Use full path so /bin and /usr/bin aren't duplicated if it's a symlink.
  for d in $dirs:A; [[ -d $d ]] && path+=($d)
  unset dirs d
typeset -U makes the $path array "unique", and :A ensures the full path is always used (in case of symlinks).

You can probably do something similar with bash, but idk.

$path is tied to $PATH and an array, so you can use it as such for some of the other things:

  print ${(F)path} | grep /bin  # (F) to print one array per line
  print ${(F)path} | sort       # can also use (o) to print ordered
  • throwaway84846 2 years ago

    I use 'path=( ${(u)^path:A}(N-/) )' instead of that for loop

    • mst 2 years ago

      To just reduce the current entries to those that exist, I'd probably do

          PATH=$(perl -e 'print join ":", grep -d, split ":", $ENV{PATH}')
      
      but that's because as a 20 year perl hacker and thus connoiseur of line noise, I'd rather read that than the shell clever.

      (this doesn't mean the shell clever is bad, it just means I don't find -that- dialect of line noise as skimmable)

      • JNRowe 2 years ago

        General point about comfort noted, but they don't do the same thing.

        $^path(N) is an equivalent to your perl expression. The snippet throwaway84846 posted also removes duplicates and collapses symlinks from /usr-merge for example.

  • adriangrigore 2 years ago

    Plan 9 from User Space binaries are on /usr/local/plan9/bin/ on OpenBSD.

  • epogrebnyakOP 2 years ago

    How does (N[-1]) get resolved?

    • arp242 2 years ago

      (N) sets the NULL_GLOB option for that pattern:

          % print doesnt-exist*
          zsh: no matches found: doesnt-exist*
          % print doesnt-exist*(N)
          (doesn't print anything, pattern is just ignored)
      
      ([n]) is array indexing to get entry n; -1 gets the last entry:

          % print a*
          a-1 a-2 a-3
          % print a*([-1])
          a-3
          % print a*([1])
          a-1
      
      Globbing is automatically sorted by name.

      So putting that together, things like this:

            ~/.local/share/gem/ruby/*/bin(N[-1])  # Ruby
      
      will use the latest Ruby version in ~/.local/share/gem/ruby, and it won't error out if it doesn't exist (so I can freely copy this around even to machines without Ruby, or remove Ruby, etc).
      • epogrebnyakOP 2 years ago

        Thanks for explaining, looks very clever. Is this syntax part of bash?

        • arp242 2 years ago

          No, bash has nothing like this. It's all very specific to zsh. They're called "glob qualifiers" if you want to find out more.

DanielKehoe 2 years ago

I'd like to hear viewpoints on using `~/.zprofile` versus `~/.zshrc` for setting `$PATH` on macOS. I was bothered for years that I didn't know the difference so I dived down the rabbit hole and wrote a guide [1]. In the end, I concluded:

- Use `~/.zprofile` to set the PATH and EDITOR environment variables. - Use `~/.zshrc` for aliases and a custom prompt, or anything tweaking the appearance and behavior of the terminal.

It seems the advantage of the `~/.zprofile` file versus `~/.zshenv` is that it sets environment variables such as `$PATH` without override from macOS. It seems the `~/.zshrc` file could be used for `$PATH` but, by convention and design, is intended for customizing the look and feel of the interactive terminal.

Frankly, saying `~/.zprofile` is better than `~/.zshrc` for setting `$PATH` only "by convention and design" feels like a cop-out. Wondering if anyone knows better.

[1] https://mac.install.guide/terminal/zshrc-zprofile

  • sidneythekidney 2 years ago

    I set $PATH in ~/.zshenv. If you don't, you can't use any of your "extra stuff" in your zsh-scripts, as they do not use login or interactive sessions. And then I unset GLOBAL_RCS so the system configfiles don't override my settings.

    In your guide, under ~/.zshenv, you mention that "macOS overrides this for PATH settings for interactive shells", without mentioning why or how. What's happening is that macOS sets your path in /etc/zprofile.

    It seems your guide is missing a few global configfiles :) This is the order for an interactive login shell [1]:

      /etc/zshenv
      ${ZDOTDIR:-$HOME}/.zshenv
      /etc/zprofile                 (login)
      ${ZDOTDIR:-$HOME}/.zprofile   (login)
      /etc/zshrc                    (interactive)
      ${ZDOTDIR:-$HOME}/.zshrc      (interactive)
      /etc/zlogin                   (login)
      ${ZDOTDIR:-$HOME}/.zlogin     (login)
      /etc/zlogout                  (login - loaded on logout)
      ${ZDOTDIR:-$HOME}/.zlogout    (login - loaded on logout)
    
    In fact, the configfiles you mention are only loaded the way you've mentioned them, if the option GLOBAL_RCS is unset. And if GLOBAL_RCS is unset, macOS does not override your PATH, because/etc/zprofile is not loaded :)

    1: <https://zsh.sourceforge.io/Doc/Release/Files.html>

    • DanielKehoe 2 years ago

      Thank you! That's informative.

      • sidneythekidney 2 years ago

        Oops, I just remembered this, and I got the order of the last two files wrong. ${ZDOTDIR:-$HOME}/.zlogout is loaded before /etc/zlogout when logging out of a login session :)

  • vim-guru 2 years ago

    Your assessment is correct. But it really comes down to what type of shell that's running. For an interactive shell (one you open yourself in a terminal), the run-com file (.zshrc) will be loaded, so anywhere you put it, things will seemingly work. But if you start doing some task scheduling etc, that would fail if you have set your PATH in a run-com.

vim-guru 2 years ago

I think for most of its use-cases, you could replace it with a one-liner: alias path='echo -e ${PATH//:/\\n} ' and work with it via sort and uniq. I've had this alias in my configuration for a couple of decades now, so I'm not bashing on its usefulness though.

  • nmz 2 years ago

    or you could just check env for a special variable and load a file once if the env var exists.

nolongerthere 2 years ago

I’m struggling to understand the use case for this aside from just checking if your own directory is on the path.

agumonkey 2 years ago

the original ~unionfs :)

nmz 2 years ago

Kinda pointless

  • rrosen326 2 years ago

    I like it! I do the steps involved in this occasionally, manually. It’s not hard but this makes it nice. Not sure I’ll use it since it is one more thing to install and remember, but the author had an itch and scratched it. Well done.

    • epogrebnyakOP 2 years ago

      Thanks! Indeed an itch that was both on Linux and Windows - so a tool that I could use in either environment

dang 2 years ago

Url changed from https://polar.sh/epogrebnyak/posts/justpath-to-explore-path-..., which points to this.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection