File::Which
WorksThe shell's which, as a function — find the full path of an executable on PATH, on every platform, before you try to run it.
- Version
1.0.4github:azawawi- Depends
- nothing outside the core
- License
- MIT
- Its own test suite
- 7 files, green
- Checked
- 2026-08-28 against Raku++ 3.20.1 and Rakudo 2026.08
Install it #
$ rakupp install File::Whichzef install File::Which writes the same store; either installer leaves the module usable by both engines.
What it is for #
Your program is about to run an external tool — git, ffmpeg, a compiler — and there are two ways to learn it is missing: a confusing failure from run at the worst moment, or a clear answer now. which is the clear answer: the same lookup the shell's which does, as a function, with the platform differences (Windows' PATHEXT extensions, macOS, plain Unix) chosen for you at load time:
use File::Which;
say which('ls');
say which('sh');
say which('definitely-not-a-program-2026').defined;/bin/ls
/bin/sh
FalseThe paths are what this machine answered — yours may differ, which is the point of asking. The result is a Str (or an undefined value for a miss), so the idiomatic guard is a with/without or .defined, and the result drops straight into run:
my $git = which('git') // die "this tool needs git on PATH";
run $git, 'status', '--short';Every hit, and fallback chains #
:all returns every match in PATH order rather than the first — the tool for diagnosing "which python am I actually getting" — and because a miss is undefined, a preference list collapses into first:
use File::Which;
my @sh = which('sh', :all);
say so @sh.elems >= 1;
say @sh[0];
my $pager = <a-fancy-pager-you-lack cat>.map({ which($_) }).first(*.defined);
say $pager;True
/bin/sh
/bin/catThe first executable that exists wins; a box with the fancy pager installed would answer differently, and that is the behaviour being asked for. There is also whence, an alias for which imported with use File::Which :whence, for people porting code that used the Perl module of the same name.
Where the two engines differ #
Nothing on this page. The PATH walk, the executability test and the platform dispatch answer identically under Raku++ and Rakudo — including $*DISTRO-based selection at BEGIN time, which is how the right per-platform implementation gets picked before the first call.
What was run to put this page here #
- Parse — every file of the distribution is parsed by Raku++ itself.
- Install —
rakupp install File::Which. This distribution is not in the zef index, so the installer resolved it from the REA archive; its one dependency is Windows-only (Win32::Registry, behind aby-distro.namegate) and is correctly skipped on this platform. - Test — the distribution's own suite: 7 files, green.
- Run — every example on this page, twice under each engine, as the site is built.
The install step is quietly the interesting one: platform-conditional dependencies (depends entries that name a different module per operating system) are a META6 corner few distributions use, and this module is where rakupp install proved it handles them.