Can I run a Perl script from stdin? - perl

Suppose I have a Perl script, namely mytest.pl. Can I run it by something like cat mytest.pl | perl -e?
The reason I want to do this is that I have a encrypted perl script and I can decrypt it in my c program and I want to run it in my c program. I don't want to write the decrypted script back to harddisk due to secruity concerns, so I need to run this perl script on-the-fly, all in memory.
This question has nothing to do with the cat command, I just want to know how to feed perl script to stdin, and let perl interpreter to run it.

perl < mytest.pl
should do the trick in any shell. It invokes perl and feeds the script in via the shell redirection operator <.
As pointed out, though, it seems a little unnecessary. Why not start the script with
#!/usr/bin/perl
or perhaps
#!/usr/bin/env perl
? (modified to reflect your Perl and/or env path)
Note the Useless Use of Cat Award. Whenever I use cat I stop and think whether the shell can provide this functionality for me instead.

Sometimes one needs to execute a perl script and pass it an argument. The STDIN construction perl input_file.txt < script.pl won't work. Using the tip from How to assign a heredoc value to a variable in Bash we overcome this by using a "here-script":
#!/bin/bash
read -r -d '' SCRIPT <<'EOS'
$total = 0;
while (<>) {
chomp;
#line = split "\t";
$total++;
}
print "Total: $total\n";
EOS
perl -e "$SCRIPT" input_file.txt

perl mytest.pl
should be the correct way. Why are you doing the unnecessary?

cat mytest.pl | perl
…is all you need. The -e switch expects the script as a command line argument.

perl will read the program from STDIN if you don't give it any arguments.
So you could theoretically read an encrypted file, decrypt it, and run it, without saving the file anywhere.
Here is a sample program:
#! /usr/bin/perl
use strict;
use warnings;
use 5.10.1;
use Crypt::CBC;
my $encrypted = do {
open my $encrypted_file, '<', 'perl_program.encrypted';
local $/ = undef;
<$encrypted_file>;
};
my $key = pack("H16", "0123456789ABCDEF");
my $cipher = Crypt::CBC->new(
'-key' => $key,
'-cipher' => 'Blowfish'
);
my $plaintext = $cipher->decrypt($encrypted);
use IPC::Run qw'run';
run [$^X], \$plaintext;
To test this program, I first ran this:
perl -MCrypt::CBC -e'
my $a = qq[print "Hello World\n"];
my $key = pack("H16", "0123456789ABCDEF");
my $cipher = Crypt::CBC->new(-key=>$key,-cipher=>"Blowfish");
my $encrypted = $cipher->encrypt($a);
print $encrypted;
' > perl_program.encrypted
This still won't stop dedicated hackers, but it will prevent most users from looking at the unencrypted program.

Related

Perl one liner inside a perl script not working

my text file contents
vi /root/text.conf
node.session.auth.authmethod = hello
so my one liner perl command replaces the above file contents by commenting with #. Works fine when run as single command
perl -pi -e 's/^(node.session.auth.authmethod\s*=\s*).*$/#\1hello/g' /root/text.conf
when the perl one liner code is executed inside perl script, it does not comment out the text.conf file contents.
$cmd ="perl -pi -e 's/^(node.session.auth.authmethod\s*=\s*).*$/#\1hello/g' /root/text.conf"
$line = `$cmd 2>&1`;$ret = $?;
Am I missing something while executing Perl one liner inside a Perl script.
Yes, use current perl process instead of forking new one. This is equivalent of your
perl -pi -e 's/^(node.session.auth.authmethod\s*=\s*).*$/#\1hello/g' /root/text.conf
one-liner,
use strict;
use warnings;
local $^I = "";
local #ARGV = "/root/text.conf";
while (<>) {
s/^(node.session.auth.authmethod\s*=\s*).*$/#\1hello/g;
print;
}
Defining your $cmd the Variable $/ will be replaced by it's value (the line separator). Then the regex will not match your line.
Try using single quotes (along with proper escaping):
$cmd ='perl -pi -e \'s/^(node.session.auth.authmethod\s*=\s*).*$/#\1hello/g\' /root/text.conf'
$line = `$cmd 2>&1`;$ret = $?;
This will prevent perl from expanding variables.
Nevertheless mpapec's answer is right, why forking a new process?

Ignoring variables in shell script while using cat>file.sh<<EOF ... EOF syntax

I have a question regarding embedding script files within a shell script. I often have a need to create a single shell script that unpacks other scripts, but really dislike having to comment out all of the embedded script's variables. Example of contents of my shell script:
echo "Hello world"
pwd
cat>embedded_perl_script<<EOF
#!/usr/bin/perl -w
\$input = \$ARGV[0];
my \$argc;
\$argc = #ARGV;
print \$input
EOF
perl embedded_perl_script
echo "Finished!"
This code works fine, but I would really like a way to avoid commenting out all of the embedded perl script's variables. Any suggestions?
Try this :
echo "Hello world"
pwd
cat>embedded_perl_script<<'EOF'
#!/usr/bin/perl -w
$input = $ARGV[0];
my $argc;
$argc = #ARGV;
print $input
EOF
perl embedded_perl_script
echo "Finished!"
Note that the EOF had changed to 'EOF' =)
Note : this technique is named here-doc

Export variable from a shell script into a perl script

Perl Code
`. /home/chronicles/logon.sh `;
print "DATA : $ENV{ID}\n";
In logon.sh , we are exporting the variable "ID" (sourcing of shell script).
Manual run
$> . /home/chronicles/logon.sh
$> echo $LOG
While I am running in terminal manually (not from script). I am getting the output. (But not working from the script)
I followed this post :
How to export a shell variable within a Perl script?
But didnt solve the problem.
Note
I am not allowed to change "logon.sh" script.
The script inside the backticks is executed in a child process. While environment variables are inherited from parent processes, the parent can't access the environment of child processes.
However, you could return the contents of the child environment variable and put it into a Perl variable like
use strict; use warnings; use feature 'say';
my $var = `ID=42; echo \$ID`;
chomp $var;
say "DATA: $var";
output:
DATA: 42
Here an example shell session:
$ cat test_script
echo foo
export test_var=42
$ perl -E'my $cmd = q(test_var=0; . test_script >/dev/null; echo $test_var); my $var = qx($cmd); chomp $var; say "DATA: $var"'
DATA: 42
The normal output is redirected into /dev/null, so only the echo $test_var shows.
It won't work.
An environment variable can't be inherited from a child process.
The environment variable can be updated in your "manual run" is because it's in the same "bash" process.
Source command is just to run every command in login.sh under current shell.
More info you can refer to: can we source a shell script in perl script
You could do something like:
#/usr/bin/perl
use strict;
use warnings;
chomp(my #values = `. myscript.sh; env`);
foreach my $value (#values) {
my ($k, $v) = split /=/, $value;
$ENV{$k} = $v;
}
foreach my $key (keys %ENV) {
print "$key => $ENV{$key}\n";
}
Well, I've find a solution, that sound nice for me: This seem robust, as this use widely tested mechanism to bind shell environment to perl (running perl) and robust library to export them in a perl variable syntax for re-injecting in root perl session.
The line export COLOR tty was usefull to ask my bash to export newer variables... This seem work fine.
#!/usr/bin/perl -w
my $perldumpenv='perl -MData::Dumper -e '."'".
'\$Data::Dumper::Terse=1;print Dumper(\%ENV);'."'";
eval '%ENV=('.$1.')' if `bash -c "
. ./home/chronicles/logon.sh;
export COLOR tty ID;
$perldumpenv"`
=~ /^\s*\{(.*)\}\s*$/mxs;
# map { printf "%-30s::%s\n",$_,$ENV{$_} } keys %ENV;
printf "%s\n", $ENV{'ID'};
Anyway, if you don't have access to logon.sh, you have to trust it before running such a solution.
Old...
There is my first post... for history purpose, don't look further.
The only way is to parse result command, while asking command to dump environ:
my #lines=split("\n",`. /home/chronicles/logon.sh;set`);
map { $ENV{$1}=$2 if /^([^ =])=(.*)$/; } #lines;
This can now be done with the Env::Modify module
use Env::Modify 'source';
source("/home/chronicles/logon.sh");
... environment setup in logon.sh is now available to Perl ...
Your Perl process is the parent of the shell process, so it won't inherit environment variables from it. Inheritance works the other way, from parent to child.
But when you run the script with backticks, as shown, the standard output of the script is returned to the Perl script. So, either modify the shell script to end with the echo $LOG statement you show, or create a new shell script that runs the login.sh and then has echo $LOG. Your Perl script would then be:
my $value = `./myscript.sh`;
print $value;

Too late for -CSD

Trying to run this little perl program from parsCit:
parsCit-client.pl e1.txt
Too late for -CSD option at [filename] line 1
e1.txt is here: http://dl.dropbox.com/u/10557283/parserProj/e1.txt
I'm running the program from win7 cmd, not Cygwin.
filename is parsCit-client.pl - entire program is here:
#!/usr/bin/perl -CSD
#
# Simple SOAP client for the ParsCit web service.
#
# Isaac Councill, 07/24/07
#
use strict;
use encoding 'utf8';
use utf8;
use SOAP::Lite +trace=>'debug';
use MIME::Base64;
use FindBin;
my $textFile = $ARGV[0];
my $repositoryID = $ARGV[1];
if (!defined $textFile || !defined $repositoryID) {
print "Usage: $0 textFile repositoryID\n".
"Specify \"LOCAL\" as repository if using local file system.\n";
exit;
}
my $wsdl = "$FindBin::Bin/../wsdl/ParsCit.wsdl";
my $parsCitService = SOAP::Lite
->service("file:$wsdl")
->on_fault(
sub {
my($soap, $res) = #_;
die ref $res ? $res->faultstring :
$soap->transport->status;
});
my ($citations, $citeFile, $bodyFile) =
$parsCitService->extractCitations($textFile, $repositoryID);
#print "$citations\n";
#print "CITEFILE: $citeFile\n";
#print "BODYFILE: $bodyFile\n";
From perldoc perlrun, about the -C switch:
Note: Since perl 5.10.1, if the -C option is used on the "#!" line, it
must be specified on the command line as well, since the standard
streams are already set up at this point in the execution of the perl
interpreter. You can also use binmode() to set the encoding of an I/O
stream.
Which is presumably what the compiler means by it being "too late".
In other words:
perl -CSD parsCit-client.pl
Because command-line options in a #! "shebang" are not passed consistently across all operating systems (see this answer), and Perl has already opened streams before parsing the script shebang, and so cannot compensate for this in some older OSs, it was decided in bug 34087 to forbid -C in the shebang. Of course, not everyone was happy with this "fix", particularly if it would have otherwise worked on their OS and they don't want to think about anything other than UTF-8.
If you think binmode() is ugly and unnecessary (and doesn't cover command-line arguments), you might like to consider the utf8::all package which has a similar effect to perl -CSDL.
Or were you using *nix, I would suggest export PERL_UNICODE="SDA" in the enclosing script to get Perl to realise it's in a UTF-8 environment.

perl mktemp and echo

i am trying to put some word in tempfile via commandline
temp file creat but word not past in tempfile
#!/usr/bin/perl -w
system ('clear');
$TMPFILE = "mktemp /tmp/myfile/devid.XXXXXXXXXX";
$echo = "echo /"hello world/" >$TMPFILE";
system ("$TMPFILE");
system ("$echo");
Please Help to Solve This
To capture the name output by mktemp, do this instead:
chomp($TMPFILE = `mktemp /tmp/myfile/devid.XXXXXXXXXX`);
But Perl can do all the things you are doing without resorting to the shell.
Avoid using external commands from perl script as much as possible.
you can use: File::Temp module in this case, see this
Here's a specific demonstration of the advice that others have given you: where possible, use Perl directly rather than invoking system. Also, you should get in the habit of including use strict and use warnings in your Perl scripts.
use strict;
use warnings;
use File::Temp;
my $ft = File::Temp->new(
UNLINK => 0,
TEMPLATE => '/tmp/myfile/devid.XXXXXXXXXX',
);
print "Writing to temp file: ", $ft->filename, "\n";
print $ft "Hello, world.\n";