如何删除与另一个文件中的元素匹配的行
How to delete lines that match elements from another file
我正在学习 Perl,我正在努力弄清楚如何完成这项任务。我有一个包含一堆文本文件的文件夹,我有一个包含三个字母列表的文件 ions_solvents_cofactors
。
我编写了一个脚本来打开和读取文件夹中的每个文件,并且应该删除特定列 [3] 下与列表中的某些元素匹配的那些行。它运作不佳。我在脚本末尾遇到了一些问题,无法弄清楚它是什么。
我得到的错误是:rm: invalid option -- '5'
我的输入文件如下所示:
ATOM 1592 HD13 LEU D 46 11.698 -10.914 2.183 1.00 0.00 H
ATOM 1593 HD21 LEU D 46 11.528 -8.800 5.301 1.00 0.00 H
ATOM 1594 HD22 LEU D 46 12.997 -9.452 4.535 1.00 0.00 H
ATOM 1595 HD23 LEU D 46 11.722 -8.718 3.534 1.00 0.00 H
HETATM 1597 N1 308 A 1 0.339 6.314 -9.091 1.00 0.00 N
HETATM 1598 C10 308 A 1 -0.195 5.226 -8.241 1.00 0.00 C
HETATM 1599 C7 308 A 1 -0.991 4.254 -9.133 1.00 0.00 C
HETATM 1600 C1 308 A 1 -1.468 3.053 -8.292 1.00 0.00 C
这是脚本:
#!/usr/bin/perl -w
$dirname = '.';
opendir( DIR, $dirname ) or die "cannot open directory";
@files = grep( /\.txt$/, readdir( DIR ) );
foreach $files ( @files ) {
open( FH, $files ) or die "could not open $files\n";
@file_each = <FH>;
close FH;
close DIR;
my @ion_names = ();
my $ionfile = 'ions_solvents_cofactors';
open( ION, $ionfile ) or die "Could not open $ionfile, $!";
my @ion = <ION>;
close ION;
for ( my $line = 0; $line <= $#file_each; $line++ ) {
chomp( $file_each[$line] );
if ( $file_each[$line] =~ /^HETATM/ ) {
@is = split '\s+', $file_each[$line];
chomp $is[3];
}
foreach ( $file_each[$line] ) { #line 39
if ( "@ion" =~ $is[3] ) {
system( "rm $file_each[$line]" );
}
}
}
}
例如,如果输入文件中的 308
在文件 ions_cofactors_solvents 中匹配,则删除所有匹配的行。
我会利用
Tie::File
模块,它允许您 tie
一个数组到模块,这样您对数组所做的任何更改都会反映在文件中
我已使用 glob
找到所有 .txt
文件,并使用选项 :bsd_glob
以支持文件路径中的空格
第一项工作是构建一个哈希 %matches
,将 ions_solvents_cofactors
中的所有值映射到 1。这使得测试 PDB 文件的所需值变得微不足道
然后只需在每个 .txt
文件上使用 tie
,并测试每一行以查看第 4 列中的值是否在散列中表示
我使用变量 $i
索引到映射磁盘文件的 @file
数组。如果找到匹配项,则使用 splice @file, $i, 1
删除数组元素。 (这自然会留下 $i
按顺序索引下一个元素而不递增 $i
。)如果没有匹配,则递增 $i
以索引下一个数组元素,将行留在原位
use strict;
use warnings 'all';
use File::Glob ':bsd_glob';
use Tie::File;
my %matches = do {
open my $fh, '<', 'ions_solvents_cofactors.txt';
local $/;
map { $_ => 1 } split ' ', <$fh>;
};
for my $pdb ( glob '*.txt' ) {
tie my @file, 'Tie::File', $pdb or die $!;
for ( my $i = 0; $i < @file; ) {
next unless my $col4 = ( split ' ', $file[$i] )[3];
if ( $matches{$col4} ) {
printf qq{Removing line %d from "%s"\n},
$i+1,
$pdb;
splice @file, $i, 1;
}
else {
++$i;
}
}
}
我正在学习 Perl,我正在努力弄清楚如何完成这项任务。我有一个包含一堆文本文件的文件夹,我有一个包含三个字母列表的文件 ions_solvents_cofactors
。
我编写了一个脚本来打开和读取文件夹中的每个文件,并且应该删除特定列 [3] 下与列表中的某些元素匹配的那些行。它运作不佳。我在脚本末尾遇到了一些问题,无法弄清楚它是什么。
我得到的错误是:rm: invalid option -- '5'
我的输入文件如下所示:
ATOM 1592 HD13 LEU D 46 11.698 -10.914 2.183 1.00 0.00 H
ATOM 1593 HD21 LEU D 46 11.528 -8.800 5.301 1.00 0.00 H
ATOM 1594 HD22 LEU D 46 12.997 -9.452 4.535 1.00 0.00 H
ATOM 1595 HD23 LEU D 46 11.722 -8.718 3.534 1.00 0.00 H
HETATM 1597 N1 308 A 1 0.339 6.314 -9.091 1.00 0.00 N
HETATM 1598 C10 308 A 1 -0.195 5.226 -8.241 1.00 0.00 C
HETATM 1599 C7 308 A 1 -0.991 4.254 -9.133 1.00 0.00 C
HETATM 1600 C1 308 A 1 -1.468 3.053 -8.292 1.00 0.00 C
这是脚本:
#!/usr/bin/perl -w
$dirname = '.';
opendir( DIR, $dirname ) or die "cannot open directory";
@files = grep( /\.txt$/, readdir( DIR ) );
foreach $files ( @files ) {
open( FH, $files ) or die "could not open $files\n";
@file_each = <FH>;
close FH;
close DIR;
my @ion_names = ();
my $ionfile = 'ions_solvents_cofactors';
open( ION, $ionfile ) or die "Could not open $ionfile, $!";
my @ion = <ION>;
close ION;
for ( my $line = 0; $line <= $#file_each; $line++ ) {
chomp( $file_each[$line] );
if ( $file_each[$line] =~ /^HETATM/ ) {
@is = split '\s+', $file_each[$line];
chomp $is[3];
}
foreach ( $file_each[$line] ) { #line 39
if ( "@ion" =~ $is[3] ) {
system( "rm $file_each[$line]" );
}
}
}
}
例如,如果输入文件中的 308
在文件 ions_cofactors_solvents 中匹配,则删除所有匹配的行。
我会利用
Tie::File
模块,它允许您 tie
一个数组到模块,这样您对数组所做的任何更改都会反映在文件中
我已使用 glob
找到所有 .txt
文件,并使用选项 :bsd_glob
以支持文件路径中的空格
第一项工作是构建一个哈希 %matches
,将 ions_solvents_cofactors
中的所有值映射到 1。这使得测试 PDB 文件的所需值变得微不足道
然后只需在每个 .txt
文件上使用 tie
,并测试每一行以查看第 4 列中的值是否在散列中表示
我使用变量 $i
索引到映射磁盘文件的 @file
数组。如果找到匹配项,则使用 splice @file, $i, 1
删除数组元素。 (这自然会留下 $i
按顺序索引下一个元素而不递增 $i
。)如果没有匹配,则递增 $i
以索引下一个数组元素,将行留在原位
use strict;
use warnings 'all';
use File::Glob ':bsd_glob';
use Tie::File;
my %matches = do {
open my $fh, '<', 'ions_solvents_cofactors.txt';
local $/;
map { $_ => 1 } split ' ', <$fh>;
};
for my $pdb ( glob '*.txt' ) {
tie my @file, 'Tie::File', $pdb or die $!;
for ( my $i = 0; $i < @file; ) {
next unless my $col4 = ( split ' ', $file[$i] )[3];
if ( $matches{$col4} ) {
printf qq{Removing line %d from "%s"\n},
$i+1,
$pdb;
splice @file, $i, 1;
}
else {
++$i;
}
}
}