sort命令用于对以特定单词开头的某些行进行排序

时间:2017-06-24 22:04:27

标签: bash

我想基于第二列对文件进行排序,但我还想只对以“@SQ”开头的行进行排序,这意味着尚未排序的行必须保持在与...相同的位置。他们首先是。

sort -k 2,2 filename

输入:

@HD     VN:1.0  SO:unsorted
@SQ     SN:chr11 LN:197195432
@SQ     SN:chr8 LN:181748087
@SQ     SN:chr6 LN:181741298
@SQ     SN:chr5 LN:111089233
@PL     ID:Me   RF:091284293

期望的输出:

@HD     VN:1.0  SO:unsorted
@SQ     SN:chr5 LN:111089233
@SQ     SN:chr6 LN:181741298
@SQ     SN:chr8 LN:181748087
@SQ     SN:chr11 LN:197195432
@PL     ID:Me   RF:091284293

3 个答案:

答案 0 :(得分:2)

您可以通过读取两个不同的文件描述符并将排序的行替换为最终输出中的未排序行来执行您需要执行的操作。基本上,您可以使用'@SQ'版本排序功能来隔离和排序以sort -V开头的行,例如

grep '^@SQ' <filename.txt | sort -V

然后,您可以通过读取第二个文件描述符逐行读取原始文件,从而可以读取stdin上面排序行的输出,例如低于FD 3的读数,

while read -r line <&3; do 
    ...
        read -r sorted
    ...
done 3<"filename.txt"

(请注意,如果您的read版本未提供-r选项,请将其删除)

将这两件放在一起,你可以做到:

grep '^@SQ' <filename.txt | sort -V |
while read -r line <&3; do 
    if [ "${line%% *}" = '@SQ' ]; then  ## line begins with '@SQ'
        read -r sorted
        echo "$sorted"
    else 
        echo "$line"
    fi
done 3<"filename.txt"

我将未分类的文件存储在dat/sortdata.txt中。您可以获得所需的输出:

示例使用/输出

$ grep '^@SQ' <dat/sortdata.txt | sort -V |
> while read -r line <&3; do
>     if [ "${line%% *}" = '@SQ' ]; then  ## line begins with '@SQ'
>         read -r sorted
>         echo "$sorted"
>     else
>         echo "$line"
>     fi
> done 3<"dat/sortdata.txt"
@HD     VN:1.0  SO:unsorted
@SQ     SN:chr5 LN:111089233
@SQ     SN:chr6 LN:181741298
@SQ     SN:chr8 LN:181748087
@SQ     SN:chr11 LN:197195432
@PL     ID:Me   RF:091284293

如果您愿意,可以通过在子shell中执行上述操作并将输出重定向到文件来将输出重定向到单独的文件。仔细看看,如果您有任何其他问题,请告诉我。

答案 1 :(得分:0)

我还在学习python,所以我不会声称它很漂亮或有效,但它确实有效。

#!/usr/bin/python3
from natsort import natsorted
import re

insq = False
sq = []
r = re.compile( r"^@SQ")
with open( "franchini", "r" ) as f:
  for line in f:
    if not r.match( line ):
      if insq:
        for i in  natsorted(sq):
          print(i)
      print( line.strip() )
      insq = False
    else:
      sq.append( line.strip() )
      insq = True

这保存为fran.py,您在franchini中的样本数据会得到以下结果:

./fran.py
@HD     VN:1.0  SO:unsorted
@SQ     SN:chr5 LN:111089233
@SQ     SN:chr6 LN:181741298
@SQ     SN:chr8 LN:181748087
@SQ     SN:chr11 LN:197195432
@PL     ID:Me   RF:091284293

答案 2 :(得分:0)

Python 解决方案:

sort_sq_lines.py 脚本:

import re, sys

with open(sys.argv[1], 'r') as f:
    lines = f.read().splitlines()
    sq_lines = []
    for l in lines:
        if l.startswith('@SQ'):
            sq_lines.append(l)
        else:
            if sq_lines:
                processed = sorted(sq_lines, key=lambda l: int(re.split(r'(\s+)', l)[2][6:]))
                print('\n'.join(i for i in processed))
            print(l)

用法:

python sort_sq_lines.py filename

输出:

@HD     VN:1.0  SO:unsorted
@SQ     SN:chr5 LN:111089233
@SQ     SN:chr6 LN:181741298
@SQ     SN:chr8 LN:181748087
@SQ     SN:chr11 LN:197195432
@PL     ID:Me   RF:091284293