【问题标题】:What could be the faster replacement of this sed command?什么可以更快地替换这个 sed 命令?
【发布时间】:2014-08-28 14:23:14
【问题描述】:

我有一个脚本,下面的 sed 命令对输入文件起作用。

 sed -i 's/SESSION_ID/sid/g;s/TIME_HOUR/hh/g;s/TIME_MINUTE/mm/g;s/TIME_SECOND/ss/g;s/TIME_MILLISECOND/mss/g;s/MSISDN/MS/g;s/IMSI/IM/g;s/IMEISV/IV/g;s/name_ALLOCATED_UE_ADDRESS_IPV4/aI4/g;s/IPV6/I6/g;s/OPERATION_TYPE/OT/g;s/LOCATION_AREA_CODE/LC/g;s/CELL_IDENTITY/CI/g;s/RAT_TYPE/RT/g;s/APN/AP/g;s/COUNTRY_CODE/CC/g;s/NETWORK_CODE/NC/g;s/name_SGSN_ADDRESS_IPV4/sI4/g;s/QCI/QC/g;s/SUBSCRIBERGROUP/SG/g;s/MONITORING_KEY/MK/g;s/QUOTA_VOLUME_BIDIRECTIONAL/QV/g;s/MBR_UL/MU/g;s/MBR_DL/MD/g;s/RULE_ID/RD/g;' $FiletosqeezE

现在的问题是......执行所需的时间比预期的要长。能否请您告知什么可以更快地替换此 sed 命令...我们甚至可以在这里借助 perl...谢谢。

【问题讨论】:

  • 您预计需要多少 时间?除非您可以利用额外的信息,例如行首的所有字符串,否则您不太可能使其更快。
  • 对不起,如果我听起来很愚蠢......但没有明白你的意思......特别是“例如在行首的所有字符串。” ....谢谢您的回复顺便说一句...
  • 给出一个输入样本,以便进行优化。您的 sed 动作列表对于所有那些“独立”模式的通用修改来说很快,但也许不是不是通用的(就像许多术语在 1 行或相反的从不在同一行,...)
  • 发布几行具有代表性的示例输入和预期输出,以便我们为您提供帮助。

标签: perl unix sed


【解决方案1】:

使用命令行 perl(将所有替换连接到一个表达式中):

perl -i -pe '
    BEGIN {
      %hash = qw(SESSION_ID sid TIME_HOUR hh TIME_MINUTE mm TIME_SECOND ss TIME_MILLISECOND mss MSISDN MS IMSI IM IMEISV IV name_ALLOCATED_UE_ADDRESS_IPV4 aI4 IPV6 I6 OPERATION_TYPE OT LOCATION_AREA_CODE LC CELL_IDENTITY CI RAT_TYPE RT APN AP COUNTRY_CODE CC NETWORK_CODE NC name_SGSN_ADDRESS_IPV4 sI4 QCI QC SUBSCRIBERGROUP SG MONITORING_KEY MK QUOTA_VOLUME_BIDIRECTIONAL QV MBR_UL MU MBR_DL MD RULE_ID RD);
      $pat = join "|", sort {length($b) <=> length($a)} keys %hash; 
    }
    s/\b($pat)\b/$hash{$1}/g;
  '  $FiletosqeezE

开关

  • -i:编辑&lt;&gt; 文件(如果提供扩展名,则进行备份)
  • -p:为输入文件中的每个“行”创建一个 while(&lt;&gt;){...; print} 循环。
  • -e:告诉perl 在命令行上执行代码。

【讨论】:

  • 我认为这值得一票,它的运行速度是我的 100M 测试文件中 sed 选项的两倍(尽管没有替换)。
【解决方案2】:

如果您需要能够真正执行每一行上的所有这些替换,那么您不太可能使其更快,至少使用sed 本身。其他工具,例如 awkperl,可能会给您带来改进。

如果您有可能利用您可能拥有的额外信息,有一些方法可以使其变得更好。

例如,如果您只希望每行中每个字符串(如SESSION_ID)出现一个,则可以去掉全局标志g,这意味着它赢了' 不为每个替换处理该行的其余部分。

或者,如果每一行只包含 一个 关键字(例如,没有包含 SESSION_ID TIME_HOUR 的行,您可以使用类似 @ 987654328@ 进行替换,并使用next 以便第一个替换立即移动到下一行,而不是检查所有其他行。

或者,如果您知道所有关键字都在该行的开头,您可以将替代项更改为:

s/SESSION_ID/sid/g

进入:

s/^SESSION_ID/sid/

这可能会加快速度,因为它不必超出前几个字符的范围。

但是,如果没有额外的信息,您可能通过为此特定目的创建一个硬编码程序而不是使用更通用的 sed 和脚本来获得更快的性能。

这样,您可以调整诸如每次读取调用加载多少数据等内容。由于您的sed 字符串是固定的而不是正则表达式,因此我不期望太多有很大的改进,但如果您愿意付出前期努力,它可能值得一试。 p>


对于它的价值,sed 命令在我的盒子上不到 12 秒就轻松通过了一个 100M 的源文件,我不认为这不好。

只要确保,无论您测试什么选项,都正确地测试它们。 衡量,不要猜测!

【讨论】:

    【解决方案3】:

    根据著名的 sed 单行文字: http://sed.sourceforge.net/sed1line.txt

    如果你像这样修改你的替换:

    sed 's/something/changed/g;s/another/one/g' 
    

    sed '/something/ s//changed/g; /another/ s//one/g' 
    

    你得到了改进,我在一个小文件上进行了测试,系统部分减半:

    (precise)cronkilla@localhost:/tmp$ time sed 's/dog/cat/g;s/fox/horse/g;s/quick/slow/g;s/the/blah/g' n4.txt > n6.txt
    
    real    0m0.043s
    user    0m0.039s
    sys 0m0.004s
    
    
    (precise)cronkilla@localhost:/tmp$ time sed '/dog/ s//cat/g;/fox/ s//horse/g;/quick/ s//slow/g;/the/ s//blah/g' n4.txt > n6.txt
    real    0m0.052s
    user    0m0.050s
    sys 0m0.002s
    

    【讨论】:

    • 我想知道为什么会这样?为什么实现不优化呢?
    • 不知道我没看过sed源代码,不过貌似还有优化的空间。
    • 您的系统时间减半既无统计学意义也无用,顺便说一句。 CPU 时间是 user+sys,从原始版本的 43 到您的版本中的 52。然而,如前所述,一个样本量对于得出结论几乎没有用处。
    • 样本量是10000行相同的“快速棕色狐狸跳过懒狗”。根据在线文档,sys 输出是 (iii) 系统 CPU 时间(times(2) 返回的 struct tms 中的 tms_stime 和 tms_cstime 值的总和)。