linux - 如何删除与另一个文件中的元素匹配的行

标签 linux perl centos protein-database

我正在学习 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 模块,它允许您将数组绑定(bind)到模块,以便您对数组所做的任何更改都反射(reflect)在文件中

我使用 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;
        }
    } 
}

关于linux - 如何删除与另一个文件中的元素匹配的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48166370/

相关文章:

Perl6 : How could I make all warnings fatal?

php - 主服务器多站点 htaccess

linux - 来自 NIC 的以太网帧

linux - ./要执行的文件路径不执行

perl - 我如何使用 Net::Server 在 Perl 中编写一个简单的聊天服务器?

perl - 当实例方法通过 "$self"引用相互调用时,在 Perl 中这是一个好习惯吗?

linux - 如何将 Crashpad 与 Linux 中的守护程序应用程序集成?有实现指南吗?

linux - QProcess 调用带有参数的 gksudo 用于调用脚本的个性化消息

sed: 非法选项 -- CentOS5 上的 i

centos - 使用 libvirt_volume.source 的 URL 时如何指定 HTTP 身份验证(用户、密码)