Perl的命令管道在sed预写路径时失败



我正在编写一个Perl程序,该程序需要调用bash脚本来搜索、排序并在每行前面插入一个路径。下面是我的剧本。

...
system("grep $a $file | grep $b | sort -uk 5,6 | sort -k 2 | sed 's/^/$dir /'");
...

其中$a$b$file$dir是变量。其中,

$dir = "/home/user/simulations/dir1/dir2/dir3/.../dirn/$file"

如果我使用一个没有/的字符串,我可以毫无问题地运行这个脚本。然而,如果我使用一个变量$dir,其中的值由/组成,我总是会得到错误消息:

sed:-e表达式#1,char 6:"s"的未知选项

因为每个目录的长度/比例不同,有没有一种简单的方法可以避免插入?如有任何建议和帮助,我们将不胜感激。

您还可以在Perl中执行所有操作(无需调用系统命令sortgrepsed(:

首先逐行读取文件,并为每行构建排序键:

while ( my $line = <$fh> ) {
chomp $line;
# IMPORTANT: $a and $b are special names in Perl, so avoid these.
#   I used here $aa and $bb...
if ($line =~ /Q$aaE/ && $line =~ /Q$bbE/) { # grep $a $file | grep $b
my @fields = split " ", $line;
my $key1 = join "", @fields[4..5];
my $key2 = $fields[1];
push @lines, [$key1, $key2, $line];
}
}

现在,由于您有@lines阵列,您可以简单地执行以下操作:

my %seen;
say for map { "$dir " . $_->[2] }
sort { $a->[1] cmp $b->[1] } 
grep { !$seen{ $_->[2] }++ }
sort { $a->[0] cmp $b->[0] } @lines;

由于这是在Perl脚本中运行的,因此没有充分的理由使用外部工具进行任何处理。Perl对这类工作有各种各样的支持,并且在这方面做得很好

use warnings;
use strict;
use feature 'say';
use List::Util qw(uniq);
my $file = shift @ARGV;
die "Usage: $0 filenamen" if not $file or not -f $file;
open my $fh, '<', $file or die "Can't open $file: $!";
my $patt1 = qr/./;  # match any one character; for testing
my $patt2 = qr/./;  # these are "$a" and "$b"
# Only lines with both patterns
my @lines = grep { /$patt1/ and /$patt2/ } <$fh>;
my $dir = '/some/path/';
my %freq;
my @sorted =
map { "$dir " . join ' ', @$_ }
grep { ++$freq{join("", @{$_}[4,5])} == 1 } 
sort { 
$a->[1] cmp $b->[1] or
$a->[4] cmp $b->[4] or
$a->[5] cmp $b->[5]
}   
map { [ split ] } 
@lines;
say for @sorted;

我使用$patt1$patt2而不是$a$b,它们是不应该使用的特殊名称(也是非常糟糕的变量名称(。为了测试,我将它们设置为与任何一个字符匹配。

在排序语句中,arrayref首先由每行的字(外部sort的字段(组成。然后这些数组按第二个字段排序,然后按第5和第6个字段排序。然后对已排序的集合进行滤波,以便只保留具有相等第5和第6字段的行的每个子集中的第一行(在这些已排序的字段中是唯一的,在外部sort中是-uk 5,6(。

最后,将这些行重新构造为字符串,并预加一个$dir

这已经用我制作的一个文件进行了测试,但由于我不确定你的管道到底要做什么,可能需要进行更改才能达到目的。

脚本从文件中提取所有行,并保留所有具有模式的行。由于sort语句的原因,内存使用量是它的数倍,对于极端大小的文件来说,这可能太多了。在这种情况下,我们会有一个外部工具有用的例子,因为当文件太大时,系统sort不会将整个文件加载到内存中。

您未正确生成sed程序(如打印"sed 's/^/$dir /'"所示(。

您也不正确地生成了shell命令。

固定:

use String::ShellQuote qw( shell_quote );
my $cmd = join(' | ',
shell_quote('grep', '--', $pattern1, $file),
shell_quote('grep', '--', $pattern2),
'sort -uk 5,6',
'sort -k 2',
shell_quote('sed', "s/^/Q$dirE /"),
);
system($cmd);

注意,我用$pattern1$pattern2替换了$a$b$a$b是特殊变量,$a and$b`是无意义的名称。

最新更新