使用Python在一个文件夹中的多个文件上一次运行Perl脚本

时间:2019-05-12 22:30:19

标签: python perl

这是我目前的perl脚本:

Math.round

这是我目前的Python脚本:

#!/usr/bin/perl
use open qw/:std :utf8/;
use strict;
use warnings;

if (defined $ARGV[0]){
my $filename = $ARGV[0];
my %count;

open (my $fh, $filename) or die "Can't open '$filename' $!";
while (<$fh>)
{
        $count{ lc $1 }++ while /(\w+)/g;
}
close $fh;

my $array = 0;

foreach my $word ( sort { $count{$b} <=> $count{$a} } keys %count)
{
    print "$count{$word} $word\n" if $array++ < 10;
}

}else{
print "Please enter the name of the file: ";
my $filename = ($_ = <STDIN>);

my %count;

open (my $fh, $filename) or die "Can't open '$filename' $!";
while (<$fh>)
{
        $count{ lc $1 }++ while /(\w+)/g;
}
close $fh;

my $array = 0;

foreach my $word ( sort { $count{$b} <=> $count{$a} } keys %count)
{
    print "$count{$word} $word\n" if $array++ < 10;
}
}

问题:当数据文件夹中有多个txt文件时,脚本仅在一个文件上运行,而忽略所有其他txt文件。有没有办法一次在所有txt文件上运行perlscript?

另一个问题:我还试图在执行后用os.remove删除txt文件,但是在perlscript有机会执行之前将其删除。

有什么想法吗? :)

1 个答案:

答案 0 :(得分:3)

该Perl脚本处理一个文件。另外,通过os.system传递给shell的字符串不会扩展为包含* shell glob所期望的带有文件列表的有效命令。

相反,请使用os.listdirglob.globos.walk在Python中构建文件列表。然后遍历列表,并在每个文件上调用该Perl脚本(如果一次只能处理一个文件),或者修改Perl脚本以处理多个文件并在整个列表中运行一次。

要保留当前的Perl脚本并在每个文件上运行它

import os

data_path   = "/home/user/Desktop/data/"
output_path = "/home/user/Desktop/result/"

for file in os.listdir(data_path):
    if not file.endswith(".txt"):
        continue

    print("Processing " + file)                      # better use subprocess
    run_perlscript = "perl " + " perlscript.pl " + \
        data_path + file  + " >> " + output_path + "output.txt"
    os.system(run_perlscript)

需要重写Perl脚本以丢失不必要的代码重复。

但是,最好使用subprocess模块来运行和管理外部命令。即使在os.system文档本身中也建议这样做。 例如

import subprocess

with open(output_path + "output.txt", "a") as fout:
    for file in os.listdir(path):
        if not file.endswith(".txt"):
            continue 
        subprocess.run(["perl", "script.pl", data_path + file], stdout=fout)

在问题的"a"重定向之后以附加模式(>>)打开文件的位置。

推荐的subprocess.run自python 3.5起可用;否则请使用Popen

另一个(可以说是“正确的”)选项是调整Perl脚本,以便它可以处理多个文件。然后,只需使用整个文件列表运行一次即可。

use strict;
use warnings;
use feature 'say';    
use open ':std', ':encoding(UTF-8)';

foreach my $filename (@ARGV) {
    say "Processing $filename";

    my %count;

    open my $fh, '<', $filename  or do {
       warn "Can't open '$filename': $!";
       next;
    };
    while (<$fh>) {   
        $count{ lc $1 }++ while /(\w+)/g;
    }   
    close $fh;

    my $prn_cnt = 0;
    foreach my $word ( sort { $count{$b} <=> $count{$a} } keys %count) {   
        print "$count{$word} $word\n" if $prn_cnt++ < 10; 
    }   
}

这会在无法打开的文件上显示警告,并跳至下一个文件。如果您希望脚本在任何意外的文件上退出,请用原始的or do { ... };替换die

然后(以glob.glob为例)

import subprocess

data_path   = "/home/user/Desktop/data/"
output_path = "/home/user/Desktop/result/"

files = glob.glob(data_path + "*.txt")

with open(output_path + "output.txt", "a") as fout:
    subprocess.run(["perl", "script.pl", files], stdout=fout)

由于这会将整个列表作为命令参数传递,因此假定没有(高)文件数超过管道或命令行的某些长度限制。