需要从文件中提取值并从Perl中的变量中减去

时间:2015-08-21 15:16:05

标签: perl awk

文件:

1,2015-08-20,00:00:00,89,1007.48,295.551,296.66,

2,2015-08-20,03:00:00,85,1006.49,295.947,296.99,

3,2015-08-20,06:00:00,86,1006.05,295.05,296.02,

4,2015-08-20,09:00:00,85,1005.87,296.026,296.93,

5,2015-08-20,12:00:00,77,1004.96,298.034,298.87

代码:

 use IPC::System::Simple qw( capture capturex );
 use POSIX;

 my $tb1_file = '/var/egridmanage_pl/daily_pl/egrid-csv/test.csv';
 open my $fh1, '<', $tb1_file or die qq{Unable to open "$tb1_file" for input: $!};

 my @t1_temp_12 = map {
        chomp;
        my @t1_ft_12 = split /,/;
        sprintf "%.0f", $t1_ft_12[6] if $t1_ft_12[2] eq '12:00:00';
 } <$fh1>;

 print "TEMP @t1_temp_12\n";

 my $result = @t1_temp_12 - 273.14;

 print "$result should equal something closer to 24 ";

$result值打印出-265.14,让我觉得@t1_temp_12已经散列

所以我试着做awk

     my $12temp = capture("awk -F"," '$3 == "12:00:00" {print $7 - 273-.15}' test.csv");

我尝试使用``,qx,open,系统使用awk命令都具有相同的错误结果

但这错误了。在命令行执行awk时,我得到了有利的结果。

2 个答案:

答案 0 :(得分:4)

这看起来像这里有一些货物崇拜节目。 看起来就像你想要做的就是找到12:00:00的行并以C度而不是K来打印温度。

可以这样做:

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

while (<DATA>) {
    my @fields = split /,/;
    print $fields[6] - 273.15 if $fields[2] eq "12:00:00";
}

__DATA__
1,2015-08-20,00:00:00,89,1007.48,295.551,296.66,
2,2015-08-20,03:00:00,85,1006.49,295.947,296.99,
3,2015-08-20,06:00:00,86,1006.05,295.05,296.02,
4,2015-08-20,09:00:00,85,1005.87,296.026,296.93,
5,2015-08-20,12:00:00,77,1004.96,298.034,298.87

打印:

25.72

您实际上不需要执行map sprintf等。(如果您确实希望对其进行格式化,可以对该输出执行printf)。

编辑:从评论中,似乎混淆的一个原因是从数组中提取元素。一个数组是零个或多个标量元素 - 你不能只将一个元素分配给另一个,因为......好吧,如果不只有一个元素会发生什么(这是通常的情况)。

给定一个数组,我们可以:

  • pop @array将返回最后一个元素(并将其从数组中删除),以便您my $result = pop @array;
  • [0]是数组的第一个元素,因此我们可以my $result = $array[0];
  • 或者我们可以将一个数组分配给另一个:my ( $result ) = @array; - 因为在左侧我们现在有一个数组,它是一个单独的元素 - @array的第一个元素进入{{1 }}。 (其余部分未在此方案中使用 - 但您可以执行$result

所以在你的例子中 - 如果你要做的是检索符合条件的值 - 作业的常规工具是my ( $result, @anything_else ) = @array; - 它通过对每个元素应用条件测试来过滤数组。

所以:

grep

我们可以减少到:

my @lines = grep { (split /,/)[2] eq "12:00:00" } <DATA>;
print "@lines";
print $lines[0];

但是因为我们想要转换我们的数组 - my ( $firstresult ) = grep { (split /,/)[2] eq "12:00:00" } <DATA>; print $firstresult; 是工作的工具。

map

首先我们:

  • 使用grep提取匹配元素。 (在这种情况下,一个,但不一定非必须!)
  • 使用map来变换列表,以便我们将每个元素转换为它的第6个字段,并减去273.15
  • 将整个批次分配到包含单个元素的列表 - 实际上只是取第一个结果,然后抛弃其余部分。

但就个人而言,我认为这有点复杂,可能很难理解 - 而是建议:

my ( $result ) = map { (split /,/)[6] - 273.15 } grep { (split /,/)[2] eq "12:00:00" } <DATA>;
print $result;

迭代您的数据,拆分 - 并测试 - 每一行,当您找到符合条件的行时,设置my $result; while (<DATA>) { my @fields = split /,/; if ( $fields[2] eq "12:00:00" ) { $result = $fields[6] - 273.15; last; } } print $result; 并保释出循环。

答案 1 :(得分:3)

@t1_temp_12是一个数组。你为什么要从中减去一个值?

my $result = "@t1_temp_12 - 273.14";

您想要这样做吗?

@t1_temp_12 = map {$_ - 273.14} @t1_temp_12;

作为shell one-liner,您可以将整个脚本编写为:

perl -F, -lanE 'say $F[6]-273.14 if $F[2] eq "12:00:00"' <<DATA
1,2015-08-20,00:00:00,89,1007.48,295.551,296.66,
2,2015-08-20,03:00:00,85,1006.49,295.947,296.99,
3,2015-08-20,06:00:00,86,1006.05,295.05,296.02,
4,2015-08-20,09:00:00,85,1005.87,296.026,296.93,
5,2015-08-20,12:00:00,77,1004.96,298.034,298.87
DATA
25.73