10

I have a lot of legacy code which shells out a lot, what i want to do is add a require or minimal code changes to make the backticks do something different, for instance print instead of running code

i tried using use subs but i couldn't get it to take over backticks or qx (i did redefine system which is one less thing to worry about)

i also tried to make a package:

package thingmbob;
use Data::Dumper;
use overload    '``'    => sub { CORE::print "things!:\t", Dumper \@_};
#this works for some reason
$thingmbob::{'(``'}('ls');
#this does the standard backtick operation
`ls`

unfourtunatly, I have no experience in OOP perl and my google-fu skills are failing me, could some one point me in the right direction?

caveat: I'm in a closed system with a few cpan modules preinstalled, odds are that i don't have any fancy modules preinstalled and i absolutely cannot get new ones

I'm on perl5.14

edit:

for the sake of completeness i want to add my (mostly) final product

BEGIN {
    *CORE::GLOBAL::readpipe = sub {
        print Dumper(\@_);
        @internal = readpipe(@_);
        if(wantarray){
            return @internal;
        }else{
            return join('',@internal);
        }
    };
}

I want it to print what its about to run and then run it. the wantarray is important because without it scalar context does not work

Nullman
  • 4,179
  • 2
  • 14
  • 30
  • `overload` won't help you. That's for when the current object that has the overload is used in a certain context, like `DateTime->now + 5` would magically work. – simbabque Mar 08 '17 at 11:36
  • It seems that `qx` cannot be overridden. See [this answer](http://stackoverflow.com/a/651990/4653379). (I am _not_ saying that you cannot accomplish what you want, in some way :) – zdim Mar 08 '17 at 11:36

1 Answers1

8

This perlmonks article explains how to do it. You can overwrite the readpipe built-in.

EXPR is executed as a system command. The collected standard output of the command is returned. In scalar context, it comes back as a single (potentially multi-line) string. In list context, returns a list of lines (however you've defined lines with $/ (or $INPUT_RECORD_SEPARATOR in English)). This is the internal function implementing the qx/EXPR/ operator, but you can use it directly. The qx/EXPR/ operator is discussed in more detail in I/O Operators in perlop. If EXPR is omitted, uses $_ .

You need to put this into a BEGIN block, so it would make sense to not require, but use it instead to make it available as early as possible.

Built-ins are overridden using the CORE::GLOBAL:: namespace.

BEGIN {
    *CORE::GLOBAL::readpipe = sub {
        print "@_";
    }
}

print qx/ls/;
print `ls`;

This outputs:

ls1ls1

Where the ls is the @_ and the 1 is the return value of print inside the overridden sub.

Alternatively, there is ex::override, which does the same under the hood, but with less weird internals.

simbabque
  • 53,749
  • 8
  • 73
  • 136