Bash 用GREP对数据进行子集划分

Bash 用GREP对数据进行子集划分,bash,awk,grep,subset,Bash,Awk,Grep,Subset,我有一个非常大的文本文件(16GB),我想尽快将其子集。 这是一个涉及的数据样本 0 M 4 0 0 0 Q 0 10047345 3080290,4098689 50504886,4217515 9848058,1084315 50534229,4217515 50591618,4217515 26242582,2597528 34623075,3279130 68893581,5149883 50628761,421

我有一个非常大的文本文件(16GB),我想尽快将其子集。 这是一个涉及的数据样本

0   M   4   0   
0   0   Q   0   10047345    3080290,4098689 50504886,4217515    9848058,1084315 50534229,4217515    50591618,4217515    26242582,2597528    34623075,3279130    68893581,5149883    50628761,4217517    32262001,3142702    35443881,3339757
0   108 C   0   50628761
0   1080    C   0   50628761
1   M   7   0
1   0   Q   0   17143989    
2   M   15  1   
2   0   Q   0   17143989    4219157,1841361,853923,1720163,1912374,1755325,4454730  65548702,4975721    197782,39086    54375043,4396765    31589696,3091097    6876504,851594  3374640,455375  13274885,1354902    31585771,3091016    61234218,4723345    31583582,3091014
2   27  C   0   31589696
每行的第一个数字是sessionID,任何带有“M”的行都表示会话的开始(数据按会话分组)。M后面的数字是一天,第二个数字是用户ID,用户可以有多个会话

我想提取与特定用户相关的所有行,对于每个会话,这些行包括所有行,直到遇到下一个“M”行(可以是任意数量的行)。作为第二项任务,我还想提取与特定日期相关的所有会话行

例如,对于上述数据,要提取用户ID“0”的记录,输出将是:

0   M   4   0   
0   0   Q   0   10047345    3080290,4098689 50504886,4217515    9848058,1084315 50534229,4217515    50591618,4217515    26242582,2597528    34623075,3279130    68893581,5149883    50628761,4217517    32262001,3142702    35443881,3339757
0   108 C   0   50628761
0   1080    C   0   50628761
1   M   7   0
1   0   Q   0   17143989    
要提取第7天的记录,输出为:

1   M   7   0
1   0   Q   0   17143989    
我相信,对于我迄今为止所取得的成就,有一个更优雅、更简单的解决方案,如果能得到一些反馈和建议,那就太好了。多谢各位

我试过的 我尝试使用pcrgrep-M直接应用此模式(在两个M之间匹配数据),但很难在换行符之间实现此功能。我仍然怀疑这可能是最快的选择,所以任何关于这是否可能的指导都是非常好的

下一部分内容非常分散,如果您已经有了更好的解决方案,则无需继续阅读

如果上述操作失败,我将问题分为两部分:

  • 第1部分:隔离所有“M”行以获得属于该用户/天的会话列表

  • grep方法很快(然后需要弄清楚如何使用这些数据)

    time grep-c“M\t.*\t$user\u id”trainSample.txt>>sessions.txt

  • 创建数组的awk方法很慢

    time myarr=$(awk'/M\t.*\t$user\u id/{print$1}'trainSample.txt

  • 第2部分:在第1部分创建的列表中提取属于会话的所有行

  • 继续使用awk方法,我对每个都运行了grep,但这太慢了(需要几天才能完成16GB)

  • 与上面的每个会话ID运行一次grep相比,在一个grep命令中使用所有会话ID要快得多(我使用8个sessionid以[1 | 2 | 3 | | | 8]格式运行它,并且每个会话ID单独运行的时间相同,即快8倍)。然而,我需要弄清楚如何动态地执行此操作

更新 实际上,我已经建立了一个只需几秒钟就能完成的工作解决方案,但它是一个混乱和僵化的bash-coe,我还没有扩展到第二个(以天为单位)案例

我想提取与特定用户相关的所有行,对于每个会话,这些行包括所有行,直到遇到下一个“M”行(可以是任意数量的行)

作为第二项任务,我还想提取与特定日期相关的所有会话行


似乎您正在处理某种平面文件,我认为bash不是适合此工作的工具。我会尝试将您的数据加载到数据库中,然后根据您的意愿查询您的数据。为了使问题更完美,请添加您的给定数据的预期输出input@dood其最终目标是将数据文件子集为a然后只将相关数据加载到数据库中。由于数据库太大,将所有内容加载到数据库中的时间太长。你可能是对的,bash不是正确的工具,尽管我被grep相对于其他方法的速度所吸引(我也用python脚本试过)@fedorqui我现在编辑了这个问题,希望这更清楚。可以“Day”吗重复一遍?我的意思是,你能不能有第7天的条目,然后是第15天的条目,然后是第7天的其他条目?这是一个很好的解决方案,谢谢!在1/41的数据块上运行这些条目需要20秒,假设它以大约14分钟的时间线性扩展,我认为这是相当合理的。如果有人有任何速度提升howev呃,我很高兴听到他们的声音。有趣的解决方案,干得好!也许你可以用一个名称来代替
p
,使其观点更相关:
switch
flag
或类似的东西。另外,
awk-v id=0'$2=“M”{flag=$4=id}标志'file
将允许将id作为变量提供。@user2071737,类似的
perl
解决方案将是
perl-ae'$p=$F[3]==0如果$F[1]eq“M”;如果$p'file
perl-ae'$p=$F[2]==7如果$F[1]eq“M”;分别打印if$p'文件
。。你能检查一下它的运行情况吗?如果几天不能重复,那么为了提高效率,当
p
在第二个脚本中从true变为false时,你可以
退出。@Sundeep这就是问题所在。好吧,我运行了几次,第一部分的平均速度约为25秒,第二部分的平均速度约为32秒,因此速度较慢而不是awk替代方案
for i in "${!myarr[@]}"; 
do 
  grep "^${myarr[$i]}\t" trainSample.txt >> sessions.txt
  echo -ne "Session $i\r"
done
$ awk '$2=="M"{p=$4==0}p' file
0   M   4   0   
0   0   Q   0   10047345    3080290,4098689 50504886,4217515    9848058,1084315 50534229,4217515    50591618,4217515    26242582,2597528    34623075,3279130    68893581,5149883    50628761,4217517    32262001,3142702    35443881,3339757
0   108 C   0   50628761
0   1080    C   0   50628761
1   M   7   0
1   0   Q   0   17143989 
$ awk '$2=="M"{p=$3==7}p' file
1   M   7   0
1   0   Q   0   17143989