Sometimes I find myself in the need to take a look at the executable files available in the current project directory, choose a suitable one and run it, potentially specifying some parameters. Unfortunately, package managers did not agree on a path, where the executable files should reside. Two examples that usually concern me are:
- PHP's
composer
puts them invendor/bin/
directory - Node's
npm
puts them intonode_modules/.bin
directory
Other languages like Go or Rust have their own package managers that might use different path still. To make the matters worse, node package manager uses a hidden folder (starting with a dot). Not to mention that both folders do not host the executable files, but instead use symbolic links to them. Using symbolic links is absolutely correct, it just complicates things a little bit further.
Note that one might argue that in case of npm
the reason to make
node_modules/.bin/
hidden is justified, because ask yourself when was the
last time you typed full path to node package binary manually? We have
npx
for that. But npx
can also run binaries from the packages that are
not installed in the local project, I would like to see them.
Zsh alias
Here's how I quickly solved the issue with an alias:
fx() { print -z $(fd -HI -tl | fzf) }
See it in action below, tested for npm
and composer
as stated above:
The alias required fd
, fzf
and zsh
to work. It is also possible to
tweak it a little to actually list all executable files with an additional
-tx
parameter:
fx() { print -z $(fd -HI -tl -tx | fzf) }
But I prefer only having symlinks listed with -tl
, because for some
reason that currently eludes me, packages supplied with package managers in
question tend to contain files that have an executable flag on all sort of
files, even README.md
. Because of this, the output including actual
executable flags is really cluttered and provides little to no practical
value. Listing only symlinks, as surprising as that may be, works much
better for listing executable files. Enjoy!