Realbin
Part 1: THE PROBLEM WITH PATHS
This page explains how to locate your Perl modules and config files reliably usingFindBin and $RealBin. When you hardcode a path into a script, deployment breaks the moment someone moves the file or wraps it in a symlink. Scripts run from different directories, but they do not know their actual location on disk. $RealBin solves that problem by giving you the real, symlink-resolved directory.
Part 2: THE MAGIC INCANTATION
Here's the spell you need:That's it. Two lines. Your script now knows exactly where it lives, and it can find modules sitting next to it or in a lib/ subdirectory.use FindBin qw($RealBin); use lib ($RealBin, "$RealBin/lib");
Let's break it down:
This importsuse FindBin qw($RealBin);
$RealBin, which contains the absolute, symlink-resolved path to the directory containing your script. It reports the real location on disk, not the directory you typed into the terminal and not some intermediate symlink.
This adds both the script's directory and itsuse lib ($RealBin, "$RealBin/lib");
lib/ subdirectory to @INC, so Perl can find your local modules.
Part 3: $Bin vs $RealBin - THE SHOWDOWN
FindBin exports several variables, but the two you'll see most often are$Bin and $RealBin. What's the difference?
Let's say you have this setup:$Bin - The directory of the script (may contain symlinks) $RealBin - The REAL directory (all symlinks resolved)
If someone runs /usr/local/bin/worker:/opt/myapp/bin/worker.pl # The actual script /usr/local/bin/worker -> /opt/myapp/bin/worker.pl # A symlink
See the problem? If your modules are in$Bin = "/usr/local/bin" # Where the symlink lives $RealBin = "/opt/myapp/bin" # Where the script REALLY lives
/opt/myapp/lib, using $Bin would look in /usr/local/lib, which is completely wrong. $RealBin follows the chain of symlinks all the way down and returns the actual directory.
Part 4: REAL-WORLD PATTERNS
Here's how I structure most of my projects:And in myapp.pl:myapp/ +-- bin/ | +-- myapp.pl +-- lib/ | +-- MyApp/ | +-- Core.pm +-- conf/ +-- settings.yaml
The beauty here is that it does not matter where you symlink the script or how you invoke it.#!/usr/bin/env perl use strict; use warnings; use FindBin qw($RealBin); use lib "$RealBin/../lib"; use MyApp::Core; my $config = "$RealBin/../conf/settings.yaml"; # Now you can load config from the right place!
$RealBin always points to the real source directory, so your paths stay correct regardless of the call chain.
Part 5: BEST PRACTICES
- Always use
$RealBinover$Binunless you specifically need the raw symlink path, and you probably do not. - Set up your lib path before you load your modules:
# GOOD use FindBin qw($RealBin); use lib "$RealBin/lib"; use MyModule; # BAD - MyModule won't be found! use MyModule; use FindBin qw($RealBin); use lib "$RealBin/lib";
- For complex projects, consider a single bootstrap approach:
use FindBin qw($RealBin); BEGIN { use lib "$RealBin/../lib"; }
- Combine with
File::Specfor maximum portability:
use FindBin qw($RealBin); use File::Spec; my $config = File::Spec->catfile($RealBin, '..', 'conf', 'app.yaml');
Part 6: THE GOTCHA
There's one edge case to know about: FindBin only works reliably at compile time. If you runeval or require later in the program, the values might not match what you expect. The fix is to capture $RealBin early:
use FindBin qw($RealBin); my $APP_ROOT = $RealBin; # Captured immediately # Later, even in evals, $APP_ROOT is solid
$RealBin is one of those boring-sounding features that solves a genuinely annoying problem. Once you start using it, you will wonder how you ever deployed scripts without it. Your scripts will finally know where they live, and that is the truth.
perl.gg