使用特定顺序的String值对文件内容进行排序

时间:2017-01-11 20:12:19

标签: bash sorting

我有一个混乱的文件内容如下:

13,13,GAME_FINISH,
1,1,GAME_START,
1,1,GROUP_FINISH,
17,17,WAGER,200.00
2,2,GAME_FINISH,
2,2,GAME_START,
22,22,GAME_WIN,290.00
2,2,GROUP_FINISH,
32,32,WAGER,200.00
3,3,GAME_FINISH,
3,3,GAME_START,
.... more lines

我对它进行了排序,目前按以下格式保存文件内容:

1,1,GAME_FINISH,
1,1,GAME_START,
1,1,GROUP_FINISH,
1,1,WAGER,200.00
2,2,GAME_FINISH,
2,2,GAME_START,
2,2,GAME_WIN,290.00
2,2,GROUP_FINISH,
2,2,WAGER,200.00
3,3,GAME_FINISH,
3,3,GAME_START,
3,3,GROUP_FINISH,
3,3,WAGER,200.00
... more lines

但是我怎样才能更好地排序以获得以下格式?第3和第4行可能并不总是存在。

1,1,WAGER,200.00
1,1,GAME_START,
1,1,GAME_WIN,500.00
1,1,BONUS_WIN_1,1100.00
1,1,GAME_FINISH,
1,1,GROUP_FINISH,
2,2, more lines...

对于初始排序,我使用了

sort -t, -g -k2 nameofunsortedfile.csv >> sortedfile.csv

添加信息:

我想按此顺序排序 - 下注,游戏开始,游戏获胜,奖金获胜,游戏结束,小组完成。我当前的排序不按此顺序排列。游戏胜利和奖金获胜可能并不总是存在。

我期待的顺序不是字典,也不是随机的。每个数字总是有一个赌注,开始,game_finish group_finish序列。 game_win,game_bonus是可选的。寻找一种方法来举例说明在所提到的预期序列中进行1,1排序,继续进行2,2做同样的事情等等。

2 个答案:

答案 0 :(得分:2)

使用标准UNIX实用程序执行此操作的最直接方法可能是为每行添加一个附加字段,该字段按照您想要的顺序对记录类型进行编码。

declare -A mapping=( ["WAGER"]=1 ["GAME_START"]=2 ["GAME_WIN"]=3 ["BONUS_WIN"]=4 ["GAME_FINISH"]=5 ["GROUP_FINISH"]=6 )
cut -d, -f3 filename.txt | while read; do echo ${mapping["$REPLY"]}; done | paste -d, - filename.txt | sort | sort -s -t, -n -k 2,3 | cut -d, -f 2-

declare语句声明了一个映射,允许您查找每种记录类型的顺序。只要符合您想要的顺序,具体值(12等)就不重要了;如果您愿意,可以使用字母或单词。

然后下一行包含以下命令:

  • cut -d, -f3 filename.txt提取您要按(WAGER或其他)
  • 排序的内容
  • while read; do echo ${mapping["$REPLY"]}; done获取每个值(WAGER等),并将其替换为关联数组mapping
  • 中相应的可排序值
  • paste -d, - filename.txt将这些值重新粘贴到filename.txt
  • 的每一行的开头
  • sort | sort -s -t, -n -k 2,3具有按字段2排序的效果,然后是字段3,然后是字段1(我们添加的字段)。如果sort可以使用三个字段作为键,我们可以在一个sort命令中执行此操作,但它最多只接受两个字段进行排序。
  • cut -d, -f 2-剥离添加的字段,为您留下原始记录,但按排序顺序

答案 1 :(得分:1)

Perl救援:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

my $i = 1;
my %order = map { $_ => $i++ }
            qw( WAGER GAME_START GAME_WIN BONUS_WIN GAME_FINISH GROUP_FINISH );

chomp( my @lines = <> );
say join ',', @$_ for sort {
    $a->[0] <=> $b->[0]
    || $order{ $a->[2] } <=> $order{ $b->[2] }
} map [ split /,/ ], @lines;

sort块告诉Perl首先按第一列排序,如果值相同,请使用与第三列对应的“order”。