【问题标题】:When running a Perl script from Python and writing the output to a file, why is the file empty?从 Python 运行 Perl 脚本并将输出写入文件时,为什么文件为空?
【发布时间】:2015-05-21 12:58:27
【问题描述】:

我有以下 Perl 脚本,它以以太网接口名称和传输速率作为参数:

#!/usr/bin/perl -w

$prevRXpacks = 0;
$prevTXpacks = 0;
$prevRXbytes = 0;
$prevTXbytes = 0;
$recentRXpacks = 0;
$recentTXpacks = 0;
$recentRXbytes = 0;
$recentTXbytes = 0;
$time_wait_default = 2;
$time_run_default = 0;
$prev = 0;
$overflow = 4 * 1024 * 1024 * 1024;
$k = 1000;
$m = $k * $k;
$format = "";
$format_value = 1;
$hdr_format = "Bytes/s";

if ( defined ($ARGV[0]) && ($ARGV[0] eq "--help") ) {
    print "Usage: $0 <device> [-r runtime] [-d delaytime]\n";
    print " -r     time to run traffic monitor in seconds (default = 0 <- forever)\n";
    print " -d     delay between two records in seconds (default = $time_wait_default)\n";
    print " -k, -K    print transfer rate in kbits/s or KBytes/s\n";
    print " -m, -M    print transfer rate in mbits/s or MBytes/s\n";
    die "\n";
}

open (OUT, "/dev/null");
select (OUT);
if ( !defined($ARGV[0]) || !`/sbin/ifconfig $ARGV[0]` ) {
    close (OUT);
    select (STDOUT);
    die "Usage $0 <device> [-r runtime] [-d delaytime] [-kmKM].\nTry --help for more.\n";
}
close (OUT);
select (STDOUT);

$time_wait = $time_wait_default;
$time_run = $time_run_default;

$i = 1;

while ( defined ($ARGV[$i]) ) {
    if ($ARGV[$i] eq "-d") {
        $time_wait = $ARGV[++$i] || $time_wait_default;
    }
    if ($ARGV[$i] eq "-r") {
        $time_run = $ARGV[++$i] || $time_run_default;
    }
    if ($ARGV[$i] eq "-K") {
        $format = $hdr_format = "KBytes/s";
        $format_value = $k;
    }
    if ($ARGV[$i] eq "-k") {
        $format = $hdr_format = "Kbits/s";
        $format_value = $k/8;
    }
    if ($ARGV[$i] eq "-M")  {
        $format = $hdr_format = "MBytes/s";
        $format_value = $m;
    }
    if ($ARGV[$i] eq "-m") {
        $format = $hdr_format = "Mbits/s";
        $format_value = $m/8;
    }

    $i++;
}

print "Traffic monitoring...\n";

# main loop
$time_loop = $time_run + time();

while ( time() < $time_loop || !$time_run ) {
    $recent = time();
    foreach $_ (`/sbin/ifconfig $ARGV[0]`) {
        if (/RX.*packets/) {
            ($blabla1, $blabla2, $blabla3) = split(/\s+/);
            ($blabla1, $recentRXpacks, $blabla2) = split(/:/, $blabla3);
        }
        if (/TX.*packets/) {
            ($blabla1, $blabla2, $blabla3) = split(/\s+/);
            ($blabla1, $recentTXpacks, $blabla2) = split(/:/, $blabla3);
        }
        if (/RX.*bytes/) {
            ($blabla1, $blabla2, $blabla3) = split(/:/);
            ($recentRXbytes) = split(/ /, $blabla2);
            ($recentTXbytes) = split(/ /, $blabla3);
        }
    }

    if ( ($recent > $prev) && $prev) {
        $interval = $recent - $prev;
#       $interval = $time_wait;

        $RXpacks = round (rate ($prevRXpacks, $recentRXpacks, $interval));
        $TXpacks = round (rate ($prevTXpacks, $recentTXpacks, $interval));
        $RXbytes = round (rate ($prevRXbytes, $recentRXbytes, $interval)/$format_value);
        $TXbytes = round (rate ($prevTXbytes, $recentTXbytes, $interval)/$format_value);

        write;
    }

    $prev = $recent;
    $prevRXpacks = $recentRXpacks;
    $prevTXpacks = $recentTXpacks;
    $prevRXbytes = $recentRXbytes;
    $prevTXbytes = $recentTXbytes;

    $time_delay = $time_wait + time();
    while (time() < $time_delay) {}
}

format STDOUT_TOP =
RX [packets/s]    TX [packets/s]    RX [@<<<<<<<]        TX [@<<<<<<<]
                   $hdr_format,           $hdr_format
.

format STDOUT =
@<<<<<<<<<<<<<<    @<<<<<<<<<<<<<<    @<<<<<<<<<<<<<<<<<<<<<<    @<<<<<<<<<<<<<<<<<<<<<<
$RXpacks,    $TXpacks,    $RXbytes." ".$format,    $TXbytes." ".$format
.

sub rate {
    my ($prev, $recent);
    ($prev, $recent, $interval) = @_;
    if (($recent = $recent - $prev) <0) {
        $recent += $overflow;
    }
    return $recent/$interval;
}

sub round {
    my ($mod, $result);
    $result = int ($_[0]);
    $mod = ($_[0] - $result) ;
    if ( $mod >= 0.5) {
        $result++;
    }
    return $result;
}

我尝试从 Python 运行上述脚本并使用以下代码将输出写入文件:

#!/usr/bin/python

import sys
import subprocess
import datetime
import os
import time

command = ["perl", "/root/Desktop/myethtraffic.pl", "eth0", "M"]

dir_name = "/root/Desktop/"

logfile = open("/root/Desktop/aa1a.txt", 'w')

proc = subprocess.Popen(command)
for line in proc.stderr:
        logfile.write(line)

文件已创建但为空。我该如何解决这个问题?

【问题讨论】:

  • 是否可以从命令行运行?
  • 如果我这样做的话 ./myethtraffic eth0 M 它可以工作

标签: python linux perl


【解决方案1】:

您可以将文件描述符传递给Popen,程序将直接写入文件,您无需读取管道。我有点困惑,因为您试图读取 stderr 而不是 stdout,所以写了一个将两个管道写入一个文件的示例。

#!/usr/bin/python

import sys
import subprocess
import datetime
import os
import time

command = ["perl","/root/Desktop/myethtraffic.pl", "eth0", "M"]

dir_name = "/root/Desktop/"

logfile = open("/root/Desktop/aa1a.txt", 'w')

proc=subprocess.Popen(command, 
    stdout=open("/root/Desktop/aa1a.txt", 'w'), 
    stderr=subprocess.STDOUT)
proc.wait()

【讨论】:

  • 我尝试了你的解决方案,但问题是如果我将 ctrl+c 发送到我的 python 脚本并停止它我的意思是 perl 脚本继续运行然后我必须通过找到 perl 的 pid 来杀死它使用 linux 中的“top”命令编写脚本并将 pid 赋予“kill”命令,任何建议
  • 您可以在子 perl 脚本中通过捕获 SIGHUP 并退出来修复它。在 python 父级中,您可以创建一个包含要杀死的进程的全局列表。在程序运行时添加/删除 Popens,并实现一个 atexit 钩子来杀死列表中的任何内容。
【解决方案2】:

参考文档https://docs.python.org/2/library/subprocess.html#popen-constructor 我认为您需要在调用POpen 时明确指定stderr=subprocess.PIPE,否则子进程stderr 将连接到您的主程序stderr。

试试这个:

proc=subprocess.Popen(command, stderr=subprocess.PIPE)

测试:

#!/usr/bin/python

import sys
import subprocess
import datetime
import os
import time

command = ["perl", "-e", "warn 'abc'"]

logfile = open("a.log", 'w')

proc=subprocess.Popen(command, stderr=subprocess.PIPE)
for line in proc.stderr:
        logfile.write(line)

编辑:您的 perl 进程实际上是写入 stderr 还是写入 stdout?

【讨论】:

  • stdout=subprocess.pipe 然后读proc.stdout?
【解决方案3】:

perl 可能不在您的路径中。 将完整路径传递给perl,而不是字符串“perl”,例如

command = ["/usr/bin/perl", ...]

另一种选择是使用 shell 运行命令,以模拟直接从命令行执行时的运行方式。

subprocess.Popen("/root/Desktop/myethtraffic.pl eth0 M", ..., shell=True)

【讨论】:

  • perl 命令执行,问题是将结果存入文件。
猜你喜欢
  • 2018-02-11
  • 1970-01-01
  • 2020-07-15
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 2014-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多