使用sed或awk删除行

使用sed或awk删除行,sed,awk,Sed,Awk,我有一个像这样的data.txt文件 >1BN5.txt 207 208 211 >1B24.txt 88 92 我有一个文件夹F1,其中包含文本文件 F1文件夹中的1BN5.txt文件如下所示 ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.79 C ATOM 421 CA SER A 207 68.627 -29.819 8.533 1.00 50.7

我有一个像这样的data.txt文件

>1BN5.txt
207
208
211
>1B24.txt
88
92
我有一个文件夹F1,其中包含文本文件

F1文件夹中的1BN5.txt文件如下所示

ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C 
ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C  
ATOM    422  C   SER A 248      70.124 -29.955   8.226  1.00 55.81           C 
ATOM    615  H   LEU B 208       3.361  -5.394  -6.021  1.00 10.00           H
ATOM    616  HA  LEU B 211       2.930  -4.494  -3.302  1.00 10.00           H 
ATOM    626  N   MET B  87       1.054  -3.071  -5.633  1.00 10.00           N  
ATOM    627  CA  MET B  87      -0.213  -2.354  -5.826  1.00 10.00           C 
ATOM    630  CB  MET B  87      -0.476  -2.140  -7.318  1.00 10.00           C 
ATOM    631  CG  MET B  88      -0.828  -0.688  -7.575  1.00 10.00           C
ATOM    632  SD  MET B  88      -2.380  -0.156  -6.830  1.00 10.00           S
ATOM    643  N   ALA B  92      -1.541  -4.371  -5.366  1.00 10.00           N  
ATOM    644  CA  ALA B  94      -2.560  -5.149  -4.675  1.00 10.00           C
F1文件夹中的1B24.txt文件如下所示

ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C 
ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C  
ATOM    422  C   SER A 248      70.124 -29.955   8.226  1.00 55.81           C 
ATOM    615  H   LEU B 208       3.361  -5.394  -6.021  1.00 10.00           H
ATOM    616  HA  LEU B 211       2.930  -4.494  -3.302  1.00 10.00           H 
ATOM    626  N   MET B  87       1.054  -3.071  -5.633  1.00 10.00           N  
ATOM    627  CA  MET B  87      -0.213  -2.354  -5.826  1.00 10.00           C 
ATOM    630  CB  MET B  87      -0.476  -2.140  -7.318  1.00 10.00           C 
ATOM    631  CG  MET B  88      -0.828  -0.688  -7.575  1.00 10.00           C
ATOM    632  SD  MET B  88      -2.380  -0.156  -6.830  1.00 10.00           S
ATOM    643  N   ALA B  92      -1.541  -4.371  -5.366  1.00 10.00           N  
ATOM    644  CA  ALA B  94      -2.560  -5.149  -4.675  1.00 10.00           C
我只需要1BN5.txt文件中包含207208211(第6列)的行。我想删除1BN5.txt文件中的其他行。像这样,我只需要1B24.txt文件中包含88,92的行

Desired output
1BN5.txt文件

ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C
ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C 
ATOM    615  H   LEU B 208       3.361  -5.394  -6.021  1.00 10.00           H  
ATOM    616  HA  LEU B 211       2.930  -4.494  -3.302  1.00 10.00           H
1B24.txt文件

ATOM    631  CG  MET B  88      -0.828  -0.688  -7.575  1.00 10.00           C
ATOM    632  SD  MET B  88      -2.380  -0.156  -6.830  1.00 10.00           S
ATOM    643  N   ALA B  92      -1.541  -4.371  -5.366  1.00 10.00           N 

不要尝试从现有文件中删除行,请尝试创建一个新文件,其中只包含您想要的行:

cat 1bn5.txt | awk '$6 == 207 || $6 == 208 || $6 == 211 { print }' > output.txt

肯定是awk的工作:

$ awk '$6==207||$6==208||$6==211 { print }' 1bn5.txt
ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C 
ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C  
ATOM    615  H   LEU B 208       3.361  -5.394  -6.021  1.00 10.00           H
ATOM    616  HA  LEU B 211       2.930  -4.494  -3.302  1.00 10.00           H 

$ awk '$6==92||$6==88 { print }' 1B24.txt
ATOM    631  CG  MET B  88      -0.828  -0.688  -7.575  1.00 10.00           C
ATOM    632  SD  MET B  88      -2.380  -0.156  -6.830  1.00 10.00           S
ATOM    643  N   ALA B  92      -1.541  -4.371  -5.366  1.00 10.00           N 
/^>/ {
    file = substr($1,2)
    next
}

{
    a[file][$1]
}

END {

    for (i in a) {

        while ( ( getline line < ("./F1/" i) ) > 0 ) {

            split(line,b)

            for (j in a[i]) {

                if (b[6]==j) {

                    print line > "./F1/" i ".new"
                }
            }
        }

        system(sprintf("mv ./F1/%s.new ./F1/%s", i, i))
    }
}
重定向以保存输出:

$ awk '$6==207||$6==208||$6==211 { print }' 1bn5.txt > output.txt

这里有一种使用
GNU awk
的方法。运行方式如下:

awk -f script.awk data.txt
awk -f script.awk data.txt
script.awk的内容

$ awk '$6==207||$6==208||$6==211 { print }' 1bn5.txt
ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C 
ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C  
ATOM    615  H   LEU B 208       3.361  -5.394  -6.021  1.00 10.00           H
ATOM    616  HA  LEU B 211       2.930  -4.494  -3.302  1.00 10.00           H 

$ awk '$6==92||$6==88 { print }' 1B24.txt
ATOM    631  CG  MET B  88      -0.828  -0.688  -7.575  1.00 10.00           C
ATOM    632  SD  MET B  88      -2.380  -0.156  -6.830  1.00 10.00           S
ATOM    643  N   ALA B  92      -1.541  -4.371  -5.366  1.00 10.00           N 
/^>/ {
    file = substr($1,2)
    next
}

{
    a[file][$1]
}

END {

    for (i in a) {

        while ( ( getline line < ("./F1/" i) ) > 0 ) {

            split(line,b)

            for (j in a[i]) {

                if (b[6]==j) {

                    print line > "./F1/" i ".new"
                }
            }
        }

        system(sprintf("mv ./F1/%s.new ./F1/%s", i, i))
    }
}
script.awk的内容:

/^>/ {
    file = substr($1,2)
    next
}

{
    a[file]=( a[file] ? a[file] SUBSEP : "") $1
}

END {

    for (i in a) {

        split(a[i],b,SUBSEP)

        while ( ( getline line < ("./F1/" i) ) > 0 ) {

            split(line,c)

            for (j in b) {

                if (c[6]==b[j]) {

                    print line > "./F1/" i ".new"
                }
            }
        }

        system(sprintf("mv ./F1/%s.new ./F1/%s", i, i))
    }
}
F1/1B24.txt的内容

ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C 
ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C  
ATOM    615  H   LEU B 208       3.361  -5.394  -6.021  1.00 10.00           H
ATOM    616  HA  LEU B 211       2.930  -4.494  -3.302  1.00 10.00           H 
ATOM    631  CG  MET B  88      -0.828  -0.688  -7.575  1.00 10.00           C
ATOM    632  SD  MET B  88      -2.380  -0.156  -6.830  1.00 10.00           S
ATOM    643  N   ALA B  92      -1.541  -4.371  -5.366  1.00 10.00           N
awk -F">" '{if($2 != ""){fname=$2}if($2 == ""){term=$1;system("grep "term" F1/"fname" >>F1/"fname"_results");}}' data.txt

我认为单靠
sed
是无法做到这一点的。您需要一个循环来读取文件data.txt。例如,使用
bash
脚本:

#!/bin/bash

# First remove all possible "problematic" characters from data.txt, storing result
# in data.clean.txt. This removes everything except A-Z, a-z, 0-9, leading >, and ..
sed 's/[^A-Za-z0-9>\.]//g;s/\(.\)>/\1/g;/^$/d' data.txt >| data.clean.txt

# Next determine which lines to keep:
cat data.clean.txt | while read line; do
   if [[ "${line:0:1}" == ">" ]]; then
      # If input starts with ">", set remainder to be the current file
      file="${line:1}"
   else
      # If value is in sixth column, add "keep" to end of line
      # Columns assumed separated by one or more spaces
      # "+" is a GNU extension, so we need the -r switch
      sed -i -r "/^[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ +$line +/s/$/keep/" $file
   fi
done

# Finally delete the unwanted lines, i.e. those without "keep":
# (assumes each file appears only once in data.txt)
cat data.clean.txt | while read line; do
   if [[ "${line:0:1}" == ">" ]]; then
      sed -i -n "/keep/{s/keep//g;p;}" ${line:1}
   fi
done

假设gnu awk,从包含
data.txt
的目录运行此命令:

ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C 
ATOM    421  CA  SER A 207      68.627 -29.819   8.533  1.00 50.79           C  
ATOM    615  H   LEU B 208       3.361  -5.394  -6.021  1.00 10.00           H
ATOM    616  HA  LEU B 211       2.930  -4.494  -3.302  1.00 10.00           H 
ATOM    631  CG  MET B  88      -0.828  -0.688  -7.575  1.00 10.00           C
ATOM    632  SD  MET B  88      -2.380  -0.156  -6.830  1.00 10.00           S
ATOM    643  N   ALA B  92      -1.541  -4.371  -5.366  1.00 10.00           N
awk -F">" '{if($2 != ""){fname=$2}if($2 == ""){term=$1;system("grep "term" F1/"fname" >>F1/"fname"_results");}}' data.txt
这将解析
data.txt
中的文件名和搜索项,然后从
awk
内部调用
grep
,将
data.txt
中列出的每个文件和项的匹配项附加到
F1
中名为
originalfilename.txt\u results
的新文件中

如果要完全替换原始文件,则可以运行以下命令:

grep "^>.*$" data.txt | sed 's/>//' | xargs -I{} find F1 -name {}_results -exec mv F1/{}_results F1/{} \;

这个解决方案使用了一些记录分隔符:“data.txt”使用>作为记录分隔符,而其他文件使用换行符

awk '
    BEGIN {RS=">"}
    FNR == 1 {
        # since the first char in data.txt is the record separator, 
        # there is an empty record before the real data starts
        next
    }
    {
        n = split($0, a, "\n")
        file = "F1/" a[1]
        newfile = file ".new"
        RS="\n"
        while (getline < file) {
            for (i=2; i<n; i++) {
                if ($6 == a[i]) {
                    print > newfile
                    break
                }
            }
        }
        RS=">"
        system(sprintf("mv \"%s\" \"%s.bak\" && mv \"%s\" \"%s\"", file, file, newfile, file))
    }
' data.txt 
awk'
开始{RS=“>”}
FNR==1{
#由于data.txt中的第一个字符是记录分隔符,
#在实际数据开始之前有一个空记录
下一个
}
{
n=拆分($0,a,“\n”)
file=“F1/”a[1]
newfile=文件“.new”
RS=“\n”
while(getline”
系统(sprintf(“mv\%s\”\%s.bak\”&&mv\%s\\%s\”,文件,文件,新文件,文件))
}
'data.txt

这将把F1中的所有文件移动到名为“备份”的tmp目录,然后在F1下重新创建生成的非空文件

mv F1 backup &&
mkdir F1 &&
awk '
NF==FNR {
   if (sub(/>/,"")) {
      file=$0
      ARGV[ARGC++] = "backup/" file
   }
   else {
      tgt[file,$0] = "F1/" file
   }
   next
}
(FILENAME,$6) in tgt {
   print > tgt[FILENAME,$6]
}
' data.txt &&
rm -rf backup
如果您也想要空文件,这只是一个很小的调整,如果您想要保留备份目录,只需在最后去掉
“&&rm..”
(无论如何,在测试期间都要这样做)

编辑:仅供参考,在这种情况下,您可以认为getline并非完全错误,因为它解析的第一个文件在结构和意图上与其他文件完全不同,因此解析一个不同于其他文件的文件不会在以后引起任何维护问题:

mv F1 backup &&
mkdir F1 &&
awk -v data="data.txt" '
BEGIN {
   while ( (getline line < data) > 0 ) {
      if (sub(/>/,"",line)) {
         file=line
         ARGV[ARGC++] = "backup/" file
      }
      else {
         tgt[file,line] = "F1/" file
      }
   }
}
(FILENAME,$6) in tgt {
   print > tgt[FILENAME,$6]
}
' &&
rm -rf backup
mv F1备份&&
mkdir F1&&
awk-v data=“data.txt”'
开始{
而((getline0){
如果(子(/>/,“”,第行)){
文件=行
ARGV[ARGC++]=“备份/”文件
}
否则{
tgt[文件,行]=“F1/”文件
}
}
}
(文件名,$6)在tgt中{
打印>tgt[文件名,$6]
}
' &&
rm-rf备份

但是正如您所看到的,它使脚本变得有点复杂(尽管效率稍高,因为现在主体中没有对FNR==NR的测试).

谢谢你的回答。你的代码与我的示例很好地配合。但是对于大文件,我没有得到正确的输出。它只打印几行。如果你在我的示例中增加行数,你可以理解其中的区别。@user1606106:Hmm。我现在就来研究一下。有没有可能发送那些大文件给我?如果可以,请使用和一些我猜是压缩的原因。@user1606106:我已经为您更新了脚本。它现在应该可以很好地处理非常大的文件。如果您有任何问题,请告诉我。HTH。@steve getline是多余的,因为awk读取一个文件中的所有行而没有它,所以就像您有一个脚本/工具在读取行{workon line}时执行
并将其修改为道德等效的
读取行{IF some condition{WHILE read otherline{workon otherline}}
。即使在安全的情况下,这也不是一个很好的方法…上面的getline方法与我发布的非getline解决方案之间的问题的简单示例。忽略初始文件。假设您希望增强脚本以额外打印每个选定文件第17行的第4个字段?使用getline方法,您需要引入一个变量,用于计算读取的行数,然后调用split(),而对于非getline,您只需使用FNR和$4。您可以删除“行”变量来免费获取拆分,但是您已经丢失了原始的$0。您可以创建一个变量来存储它…明白吗?这只是一个混乱的解决方法。谢谢您的回答。当我运行您的代码时,我收到错误“预期一元运算符”。如何解决此错误?在我的环境中,对我来说可以。但建议将
[
更改为
[[
可能会有帮助,将
]
更改为
]]
。这是否有效?更好的建议是:将两个
${line:0:1}
替换为
“${line:0:1}”
。您的
data.txt
可能有一个空行或类似的内容。我添加了对data.txt的初始清理,以删除除a-Z、a-Z、0-9、leading>和之外的所有内容,以防一些无关字符破坏script.uooc,并且对于包含以空格开头或结尾的行或包含反斜杠或alrea的文件将失败请记住keep这个词。谢谢你的回答。当我运行你的代码时,我在表达式中遇到了错误^invalid char“”。如何解决这个错误?不知道。我在测试时没有遇到任何错误。你是否剪切、粘贴或重新键入了?如果文件名包含空格,并且不安全地使用getline,则会失败(不测试它的返回)。也不确定所有非呆滞AWK(只允许RS中的单个字符)是否会处理
RS=“\n”