我正在编写一个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中执行所有操作(无需调用系统命令sort
、grep
和sed
(:
首先逐行读取文件,并为每行构建排序键:
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`是无意义的名称。