如何使用几个字符长的分隔符进行排序?

如何使用几个字符长的分隔符进行排序?

输入:

$ cat a.txt 
1FOO2FOO3
4FOO5FOO5
2FOO1FOO9
$ 

输出:

$ cat a.txt | sort SOMEMAGIC
2FOO1FOO9
1FOO2FOO3
4FOO5FOO5
$ 

问题:如果我有几个字符长的分隔符,我该如何排序? (“FOO”)?

在示例中a.txt按第二列排序。

问题是一般来说,数字a.txt可以是任何东西。

答案1

使用egsed将字符串替换为单字符分隔符,按列排序,然后再次替换回分隔符:

sed -e s/FOO/X/g a.txt | sort -k 2,2 -t X | sed -e s/X/FOO/g 

这假设您知道有一个字符未出现在输入中。控制字符是常见的候选字符,但您需要根据您对输入格式的了解做出选择。

答案2

尝试这个:

$ perl -ane '
    push @h,[$_,(split(/FOO/))[1]];
    END {
        print map  { $_->[0] }
              sort {$a->[1] <=> $b->[1]}
              @h;
    }
' file
2FOO1FOO9
1FOO2FOO3
4FOO5FOO5

解释

  • 将每个数组 ref [line, key] 存储在 array 中@h[$_,(split(/FOO/))[1]]

  • 当完成读取文件时:

    • @h按键对数组中的数组引用进行排序sort {$a->[1] <=> $b->[1]}
    • 从中提取原始行@h并打印map { $_->[0] }

答案3

假设您的字段是数字,GNUsort版本排序可能有帮助。将分隔符设置为F,以便尾部OOfromFOO进入字段 2 并且字段 2 被视为sort包含 value OO2, OO5 and OO1。在字段 2 上指定版本排序可确保忽略非数字前缀OO,并且输出按字段 2 的尾随数字部分排序

sort -k2,2V -t 'F' a.txt
2FOO1FOO9
1FOO2FOO3
4FOO5FOO5

或者使用 GNU awk,如果您可以忍受内存中解决方案的开销:

awk -F'FOO' '{a[$2]=$0};END{asort(a, b, "@ind_num_asc");
for (i in b) print b[i]}' a.txt
2FOO1FOO9
1FOO2FOO3
4FOO5FOO5

答案4

我认为您不必过多关注分隔符,而应该关注sort -k眼睛。您可以为键指定字符范围。

info sort

...给定输入行“foo bar”,sort将其分成字段“foo”和“bar”。字段分隔符不被认为是前面字段或后面字段的一部分,因此使用“sort -t”“”,同一输入行具有三个字段:空字段、“foo”和“bar”。但是,延伸到行尾的字段(如“-k 2”)或由范围组成的字段(如“-k 2,3”), 保留范围端点之间存在的字段分隔符

正如 Stephane 所评论的那样,反之亦然 - 您可以仅对具有字节范围的字段的切片进行排序,甚至可以对具有多个键的同一字段的多个切片进行排序。因此,在您的情况下,您可以多次使用具有不同范围的同一字段。看?

sort -k1.5n -k1.1n --debug <<\DATA
1FOO2FOO3
4FOO5FOO5
2FOO1FOO9
DATA
sort: using simple byte comparison
sort: leading blanks are significant in key 1; consider also specifying 'b'
sort: key 1 is numeric and spans multiple fields
sort: key 2 is numeric and spans multiple fields
2FOO1FOO9
    _
_
_________
1FOO2FOO3
    _
_
_________
4FOO5FOO5
    _
_
_________

这指示sort对主键进行排序,从字段 1 中的第 5 个字节开始,一直延伸到字段 1 的末尾,然后从字段 1 中的第 1 个字节到字段 1 的末尾进行排序。正如我希望上面所展示的那样,该--debug选项在尝试排序时非常有用。sort但这里是没有调试的:

sort -k1.5n -k1.1n <<\DATA        
1FOO2FOO3
4FOO5FOO5
2FOO1FOO9
DATA

###OUTPUT###
2FOO1FOO9
1FOO2FOO3
4FOO5FOO5

如果您只想sort为每个字符使用一个字符,则需要缩小范围。在上面的示例中,-k1.5n从字节 5 到字段结束工作,因为关键规范的工作方式如下:

 -k[begin field].[first byte in key],[end field].[last byte in key]

因此,虽然这种情况的结果是相同的,但您可以在打开它的同一字节上关闭每个字段范围,如下所示:

sort -k1.5,1.5n -k1.1,1.1n

因此sort每个密钥仅由一个字节组成。

相关内容