【问题标题】:perl system call not executing randomlyperl系统调用不是随机执行的
【发布时间】:2023-03-28 02:26:01
【问题描述】:

在 perl 脚本的循环结构中,我编写了以下几行来使用系统工具解析文本文件,在此过程中生成临时文本文件,然后将临时输出读入数组以在 perl 脚本中进行处理:

system("awk '(NR+2)%4==0' $infile[$i+$j] | tre-agrep -ns -E $dist[$a][$b] -k $query[$a][$b] | awk 'BEGIN{FS=\":\";OFS=\":\"}{print \$1,\$2}' > $outfile");
open(my $FH, "<", $outfile) || die "Can't open $outfile: $!";
while(<$FH>) {
  ...
}
close($FH);

这些命令几乎逐字重复两次(修改了一些参数,但回收了文件句柄)在一个循环结构中,该循环结构本身被迭代了很多次。出乎意料且看似武断,程序有时无法完成系统调用,导致依赖于系统调用生成的输出的后续行依次失败,从而触发脚本中止并显示相当无用的错误消息“没有这样的文件或目录”(参考open 语句)。直接从控制台而不是在 perl 脚本的上下文中执行相同的系统调用表明该命令产生了预期的输出。我将此行为称为任意行为,因为有时我的脚本会完成 1 到 3 次迭代,然后在 open 行失败,并且不同成功的基础尚不清楚。当脚本正常工作时,系统调用需要相当长的时间(大约 2 分钟),而当它失败时,程序会在不到一秒的时间内移动到下面的 open 行。因此,我想弄清楚为什么有时会跳过系统调用。

脚本在 bash shell 会话中运行,脚本头中包含以下内容:

#! /usr/bin/perl
use warnings;
use strict;

【问题讨论】:

  • Perl 内部一般不需要调用awk; Perl 可以做大部分 awk 可以做的事情,编写本机 Perl 代码将帮助您避免 system() 和讨厌的 shell 引用问题。
  • 见:the XY problem。这里有很多可能出错的地方;我怀疑被插值的变量可能包含未转义的空格/元字符。如果 system() 确实有问题,则加入IPC::System::Simple 将为您进行所有必要的诊断。我强烈建议您使用有关您尝试解决的问题性质的信息来编辑问题。就像 TheSuitIsBlackNot 所说的那样,一个纯粹的 Perl 解决方案会比你现在做的更简单、更健壮。 Text::Fuzzy 可以在这里替换 agrep。

标签: perl exec


【解决方案1】:

我基本上同意@ThisSuitIsBlackNot。但是,不知道tre-agrep 是什么,很难将那部分直接翻译成Perl。

也就是说,至少,为什么不跳过输出文件的生成,直接从 Perl 读取 Unix 输出?

open my $FH, '-|', "awk '(NR+2)%4==0' $infile[$i+$j] | " .
    "tre-agrep -ns -E $dist[$a][$b] -k $query[$a][$b]" or die "$!";
while (<$FH>) {
  chomp;
  my ($field1, $field2) = split /:/, $_, 2;
}
close $FH;

在最坏的情况下,系统调用的标准输出会是空白的,但这不会影响 Perl 什么都不读取(因此什么也不做)的能力。

当然,首先执行 -e(存在)调用以确保 infile[$i + $j] 不是幽灵并没有什么坏处。

【讨论】:

  • 谢谢,我没有意识到可以以这种方式在 open 语句中使用管道。正如您所指出的,这消除了对中间文件的需要,并且您提出的 open 声明已经解决了我在原始问题中提到的问题。但是,当程序重新进入循环并尝试使用文件句柄$FH 打开一个新管道时,程序将关闭并显示错误“无法分配内存”(参考包含open 语句的行)。您对如何解决此问题有任何建议吗?谢谢!
  • PS:tre-agrep 命令是近似 grep (agrep) 的开源实现,它允许近似模式匹配(基于参数化编辑距离或 Levenshtein 度量的匹配)。
  • 这可能是系统调用出错。文件有多大,您是否有足够的空间分配给交换?
  • 其实内存分配问题是无关的。这只是程序中使用的数组大小(大约 200 万乘 2x2x2)太大的事实。因此,现在一切似乎都令人满意。感谢您的帮助。
  • 我们在同一时间发布了我们的 cmets。是的,问题只是超出了我的可用系统内存(4 GB RAM,4 GB 交换),因为上一步中生成的数组的大小(我用零初始化了一个大数组),尽管我有点惊讶包含 1600 万个元素的数组需要超过 8 GB 的内存(我的系统内存的基线利用率很低,因此几乎所有元素都可用于脚本)。我将研究是否可以将数组类型转换为 8 位整数,以减少脚本的内存占用。
猜你喜欢
  • 2016-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多