BASH comm命令,但适用于多列

时间:2016-05-11 18:09:36

标签: bash unique comm

我正在寻找类似于bash命令comm的东西,我可以使用它来选择我的2个文件所特有的并且对它们来说是常见的条目。 当我每个文件只有一列时,Comm工作得很好,例如。

 comm -13 FILE1.txt FILE2.txt > Entries_only_in_file1.txt

但是现在我希望保留多列信息。我想选择第2列作为筛选我的两个文件之间的唯一和公共条目的行的列。如果第二列中的条目出现在两个文件中,我还想在第3,4和5列中记录信息(如果可能,这并不重要)。 这是输入和输出的示例。

FILE1.txt
NM_023928   AACS    2   2   1
NM_182662   AADAT   2   2   1
NM_153698   AAED1   1   5   3
NM_001271   AAGAB   2   2   1


FILE2.txt
NM_153698   AAED1   2   5   3
NM_001271   AAGAB   2   2   1
NM_001605   AARS    3   40  37
NM_212533   ABCA2   3   4   2

想要输出:

COMMON.txt
NM_153698   AAED1   1   5   3   2   5   3
NM_001271   AAGAB   2   2   1   2   2   1

UNIQUE_TO_1.txt
NM_023928   AACS    2   2   1
NM_182662   AADAT   2   2   1

UNIQUE_TO_2.txt
NM_001605   AARS    3   40  37
NM_212533   ABCA2   3   4   2

我知道之前有过类似的问题,但我找不到我想要的东西。非常感谢任何想法,谢谢。

3 个答案:

答案 0 :(得分:1)

join具有以下对您的任务有用的选项:

  • -j FIELD:加入字段FIELD
  • -o FORMAT:指定输出格式,以逗号分隔的FILENUM.FIELD列表。
  • -v FILENUM:仅在FILENUM输出行。

两个文件共通:

$ join -j2 -o 1.1,1.2,1.3,1.4,1.5,2.3,2.4,2.5 FILE1.txt FILE2.txt 
NM_153698 AAED1 1 5 3 2 5 3
NM_001271 AAGAB 2 2 1 2 2 1

FILE1独有:

$ join -j2 -v1 FILE1.txt FILE2.txt 
AACS NM_023928 2 2 1
AADAT NM_182662 2 2 1

FILE2独有:

$ join -j2 -v2 FILE1.txt FILE2.txt 
AARS NM_001605 3 40 37
ABCA2 NM_212533 3 4 2

答案 1 :(得分:0)

对于每个文件的通用行,您可以在每个文件上使用join命令和sort

摘自join

的手册页
 -v file_number
         Do not display the default output, but display a line for each
         unpairable line in file file_number.  The options -v 1 and -v 2
         may be specified at the same time.

 -1 field
         Join on the field'th field of file1.

 -2 field
         Join on the field'th field of file2.

因此,对于具有特定于文件1的列的两个文件的join将从

获得
$ join -v 1 <(sort file1.txt) <(sort file2.txt) 
NM_023928   AACS    2   2   1
NM_182662   AADAT   2   2   1

文件2上的相同内容将产生

$ join -v 2 <(sort file1.txt) <(sort file2.txt)
NM_001605   AARS    3   40  37
NM_212533   ABCA2   3   4   2

对于公共部分,我假设你需要那些列2相同的行,我做了以下方法。获取文件中的常用列并写入文件说file3.txt

$ join <(sort file1.txt) <(sort file2.txt) > file3.txt
$ cat file3.txt
NM_001271   AAGAB   2   2   1 AAGAB  2   2   1
NM_153698   AAED1   1   5   3 AAED1  2   5   3

现在使用awk我可以将重复的第6列排除为

$ awk '{$6=""; print $0}' file3.txt
NM_001271   AAGAB   2   2   1  2   2   1
NM_153698   AAED1   1   5   3  2   5   3

这是您所期望的输出。

答案 2 :(得分:0)

你可以用gnu awk来表示,这是一个脚本:

<强> script.awk

function unique(filename, line) {
    split( line , tmp, FS)
    print tmp[1], tmpp[2], tmp[3], tmp[4], tmp[5] >> filename
}

NR == FNR { # in case we are reading the first file: store line under key
        file1[ $2 ] = $0
        next
    }

    {
        if( $2 in file1 ) { # key from file2 was in also in file1:
            split( file1[ $2 ], tmp, FS)
            print $1, $2, tmp[3], tmp[4], tmp[5], $3, $4, $5 >> "COMMON.txt"
   # remove common key, thus we can later find unique keys from file1
            delete file1[ $2 ] 
        }
        else { # unique key from file2 
            unique("UNIQUE_TO_2.txt", $0)
        }
    }

END {
  # remaining keys are unique in file1
        for( k in file1 ) {
            unique("UNIQUE_TO_1.txt", file1[ k ])
        }
    }

像这样使用:

# erase the output files if present
rm -f COMMON.txt UNIQUE_TO_1.txt UNIQUE_TO_2.txt
# run script, create the file
awk -f script.awk FILE1.txt FILE2.txt
# output the files
for f in COMMON.txt UNIQUE_TO_1.txt UNIQUE_TO_2.txt; do echo "$f"; cat "$f"; done

printf ... >> filename将文本附加到文件名。第二次运行脚本时,这需要rm输出文件。