Pablo Murillo
Pablo Murillo

Reputation: 9

How to intercept execution of a perl script using a shell script and then actually execute them?

The question is a bit complicated, first I'm going to put you in situation. I have a web server with many domains and I want to know which perl scripts run the users in each domain and with which parameters.

For this I thought of renaming the perl, and create a script that is called perl that saves in a log the environment and then execute the script in perl

The script is very simple, but obviusly have something wrong

#!/bin/sh 

when=`date "+%Y%m%d%H%M%S"`
log_file="/var/logs/perl/${when}"
env > log_file
parameters=$@
echo "Parameters: $parameters" >> $log_file
/usr/local/bin/perl_bin $parameters

I use a simple perl script to test:

#!/usr/bin/perl

print "Working\n\n";

Now, the problem If I run the perl script from the shell like this:

perl script.pl

Works Ok

But If I run the perl script from the shell like this:

./script.pl

Don´t works and the error looks:

./script.pl: line 3: print: command not found

What am I missing ?

Upvotes: 0

Views: 156

Answers (1)

Schwern
Schwern

Reputation: 164799

As mentioned in the comments, this is probably overkill for your purposes and you risk subtly breaking every Perl program on your server (for example, you're passing parameters incorrectly). You're better off using your server logs or something at the kernel level like lsof. Or ask yourself why you need to know which programs your users are running at all.

But it's handy to understand what's going on.


The program in #! must be a compiled executable. It cannot be interpreted. For example...

$ cat /Users/schwern/tmp/notperl 
#!/bin/sh

perl "$@"

$ cat /Users/schwern/tmp/test.pl 
#!/Users/schwern/tmp/notperl

print "Hello, world!\n";

$ /Users/schwern/tmp/notperl /Users/schwern/tmp/test.pl
Hello, world!

$ /Users/schwern/tmp/test.pl
/Users/schwern/tmp/test.pl: line 3: print: command not found

What's happening is test.pl is executed and the program loader sees the shebang line. It then checks to see if that is an absolute path to an executable program. Not just any executable, but one that can be executed by the kernel directly.

Since /Users/schwern/tmp/notperl is interpreted, the kernel ignores the #! line and hands it off to the shell to execute. The shell has no print function and tells you so.


One generally gets around this with /usr/bin/env. This is a little program to execute another program in a modified environment. With no options it just executes the program.

$ cat /Users/schwern/tmp/test.pl 
#!/usr/bin/env /Users/schwern/tmp/notperl

print "Hello, world!\n";

$ /Users/schwern/tmp/test.pl
Hello, world!

In this case the kernel executes /usr/bin/env with the argument /Users/schwern/tmp/notperl. /usr/bin/env then executes /Users/schwern/tmp/notperl.

Upvotes: 7

Related Questions