0

My question is pretty similar to this one.

My perl script is invoked by an incoming mail via a procmail recipe. The perl script is being executed, and there are no syntax errors (or at least I get no warnings in the procmail logs and perl -c sounds OK).

My python script returns a tuple of five strings based on the input string.

And I want to use them after calling this from the Perl script. I am trying (code snippet)

my ($var1, $var2, $var3, $var4, $var5) = `./parse_input.py $input`;
print "var1 is $var1";

While parse_input returns a tuple as per the below...

return (var1, var2, var3, var4, var5)

I've tested running parse_input.py on my input strings directly, and that works fine. I am successfully redirecting print statements in the Perl script to a logging file. I.e. I see other print statements fine. But the "var1 is $var1" line just comes out as "var1 is".

Maybe I am being too ambitious though and should work on spliting it into five functions that each return one value?

Edit: Here's the relevant part of my python script.

#! <path>/python3
import sys
import re
import subprocess
input_to_parse = sys.argv[1]


def main():

    blah blah blah

    print(var1)
    print(var2)
    print(var3)
    print(var4)
    print(var5)
    return (var1, var2, var3, var4, var5)

if __name__ == "__main__":
    sys.exit(main())
4
  • 3
    Please show the Python script. The return statement in python returns a value to calling Python function, not to the shell that runs the Python script. To return a value to the shell, you can use e.g. sys.exit() from Python, also note that the backticks in Perl captures the STDOUT of the program run (which is not the same as the exit code) Commented Nov 30, 2019 at 14:50
  • 1
    I really do not know Perl at all. Given I am capturing the stdout with my backticks, should I just get rid of the return statement, and just do something like 'print("{}, {}, {}, {}, {}".format(var1, etc...))? And then perl would work that out? Commented Nov 30, 2019 at 16:20
  • 1
    Yes that would be an approach. If the arguments to be transferred are becoming more complicated I would recommend transferring the data using a JSON file instead Commented Nov 30, 2019 at 16:23
  • 1
    Piping through STDOUT / STDIN using the shell, and data interchange formats are solved problems. In your Perl script reading from backticks reads from STDIN. If your Python script printed to STDOUT a well-known light-weight data format such as JSON, the Perl script could easily parse it with the JSON module (or JSON::PP if you are tied to core-only modules) Commented Nov 30, 2019 at 16:52

1 Answer 1

4

Instead of using STDOUT for transferring variable information, you're best using a mechanism that is built for this type of purpose. Here's an example using JSON. We dump the data from the Python script as a JSON string into a file, and after the Python script has completed, we read in the JSON string from the file and proceed.

Python script:

import json

data = (1, 2, 3, 40, 50)

with open('data.json', 'w') as jsonfile:
    json.dump(data, jsonfile)

Perl script:

use warnings;
use strict;

use JSON;

my $file = 'data.json';
my $py_script = 'python.py';

# call the python script

system('python3', $py_script);

# read in json from Python

my $json;

{
    local $/;
    open my $fh, '<', $file or die $!;
    $json = <$fh>;
    close $fh;
}

# decode the Python tuple into a Perl array (reference) from the JSON string

my $array = decode_json $json ;

for my $elem (@$array){
    print "$elem\n";
}

Output:

1
2
3
40
50

Note that I'm using a file on disk for the transfer in this example, but you can use any mechanism to transfer the string (shared memory, database, etc).

If you really do want to use the command line to pass the information, that's still possible, but I'd still use JSON. If the output of the Python script is something unexpected, perl will know it:

Python:

import json

print(json.dumps((1, 2, 3, 40, 50)))

Perl:

use warnings;
use strict;

use JSON;

my $json = `python3 python.py`;

my $array = decode_json $json;

for my $elem (@$array){
    print "$elem\n";
}
Sign up to request clarification or add additional context in comments.

2 Comments

why use a file instead of stdout?
This looks amazing. I'll give it a go later :)! Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.