Stupid Command Line Tricks
The Basics of
perl understands a bunch of command line switches. Some of them, like
-f, you will probably never use. Others, like
-d, you might use all the time. The
-M switch is somewhere in between. You might use it in the most trivial case, but it can probably do a lot more than you know it can.
The general use case is this:
The general effect is that "
use Carp::Always::Color;" is injected at the beginning of the program to be run, as if it had been in the source itself. It's great for things that affect the global execution environment, like Carp::Always, but it's got a bunch of other little uses.
If you want to write a one-liner that needs an import, for example, you can use the equals sign:
The string after the
= is passed to List::Util's
import routine. If it has commas, the string is split on commas and the result is passed in.
This is how local::lib's one-liner form works! local::lib has a tricky
import routine, and you pass it a path name by using
import is called with no arguments, because libraries given to the
-M switch are loaded with
use Module;. You can skip the imports by using
use Module ();.
Usually, if I want to know what version(s) of a module I have installed, I run which_pm, but when I don't have it – or more likely, when giving advice to someone on IRC, I can use
-M. If I think someone's seeing a bug because they've got an old version of Sub::Exporter, I can tell them to run:
Most of the time, we load libraries with
no is useful, too. (Instead of calling
import, it calls
no is used by libraries that are loaded to forbid undesirable behavior. indirect lets you ban indirect method invocation. circular::require lets you ban circular module loading.
In your source for Foo.pm, you might write:
...but circular::require affects the global behavior of
require. You probably don't want to always load it everywhere. You just want to use it sometimes when testing. You can't say
-Mcircular::require, because that would use
use instead of
no. To get
no, just throw in another dash:
The code above will be silent if Foo has no circular requirements, and emit a string of warnings of it has them.
So, for testing versions, I showed:
For importing, I showed:
What if we want to combine these? They're not really compatible. What if we want to pass something more complex than a list of strings? The bits after the equals sign aren't
evaled, so they can't be complex.
The secret lies in understanding how that version-testing code worked. The space after "String::Truncate" and everything following that is just tacked into the template
use MODULE REST ;
This means you can put almost anything there. Do you want to import a renamed version of
trunc, but only if you have a recent version?
Your program will be run with the following line of code prepended:
This is where it gets a little nutty:
perl doesn't care whether you give it more than one statement. You can put all kinds of stuff in
-M's argument. In fact, if the stuff you want to put in is important, but the module isn't, you can just use something meaningless like
use 5 just ensures that you're under Perl 5 or later, and then the code you actually wanted to inject is added.
-M is a powerful tool for all kinds of code injection when you don't want to actually start editing the code you're running. Even better, once you've finished working with it, you can just delete your shell history file, and nobody will know the kind of horrible things you did with it.