4

我有一个像这样的文件 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 

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

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 文件中包含 207,208,211(第 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 
4

7 回答 7

5

这是使用GNU awk. 像这样运行:

awk -f script.awk data.txt

内容script.awk

/^>/ {
    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 '/^>/ { 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)) } }' data.txt


如果您有旧版本的awk, 早于GNU Awk 4.0.0,您可以尝试以下操作。像这样运行:

awk -f script.awk data.txt

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))
    }
}

或者,这是单线:

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)) } }' data.txt


请注意,此脚本完全按照您的描述进行。它期望像1BN5.txt和一样1B24.txt的文件驻留在F1当前工作目录的文件夹中。它还将覆盖您的原始文件。如果这不是所需的行为,请挂断system()电话。HTH。

结果:

内容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    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 

内容F1/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
于 2012-12-11T13:38:45.833 回答
1

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

cat 1bn5.txt | awk '$6 == 207 || $6 == 208 || $6 == 211 { print }' > output.txt
于 2012-12-11T12:41:17.977 回答
1

假设 gnu awk,从包含以下内容的目录运行此命令data.txt

awk -F">" '{if($2 != ""){fname=$2}if($2 == ""){term=$1;system("grep "term" F1/"fname" >>F1/"fname"_results");}}' data.txt

这会解析data.txt文件名和搜索词,然后grep从内部调用awk以将列出的每个文件和词的匹配项附加到被调用data.txt的新文件中。F1originalfilename.txt_results

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

grep "^>.*$" data.txt | sed 's/>//' | xargs -I{} find F1 -name {}_results -exec mv F1/{}_results F1/{} \;
于 2012-12-11T17:36:18.870 回答
1

此解决方案使用记录分隔符玩了一些技巧:“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 
于 2012-12-11T21:47:47.390 回答
1

这会将 F1 中的所有文件移动到名为“backup”的 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

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

于 2012-12-12T12:47:37.557 回答
0

绝对是一份工作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 

重定向以保存输出:

$ awk '$6==207||$6==208||$6==211 { print }' 1bn5.txt > output.txt
于 2012-12-11T12:44:16.057 回答
0

我不认为你一个人可以做到这一点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
于 2012-12-11T14:34:08.073 回答