【问题标题】:awk error "makes too many open files"awk 错误“打开的文件太多”
【发布时间】:2014-06-23 21:48:19
【问题描述】:

我有一个基于 awk 的拆分器,它根据正则表达式拆分一个巨大的文件。但问题是我收到了一个 make too many files 错误。即使我有条件关闭。如果您能帮助我找出我做错了什么,我将不胜感激。

    awk 'BEGIN { system("mkdir -p splitted/sub"++j) }
    /<doc/{x="F"++i".xml";}{
     if (i%5==0 ){
       ++i;
       close("splitted/sub"j"/"x);
       system("mkdir -p splitted/sub"++j"/");
      }
     else{
       print > ("splitted/sub"j"/"x);
     }
    }' wiki_parsed.xml

【问题讨论】:

  • 你不能只用csplit吗?
  • 我尝试使用 csplit,但据我所知,使用 csplit 无法创建递归目录。所以我选择了 awk。
  • 在这种情况下使用 awk 不好。您的 awk 命令中有很多纯 shell 命令。直接写在shell脚本中

标签: regex bash shell awk


【解决方案1】:

这就是我让它完美工作的原因

    awk 'BEGIN { system("mkdir -p splitted/sub"++j) }
     /<doc/{x="F"++i".xml";}{

      if (i%1995==0 ){
       ++i;
       system("mkdir -p splitted/sub"++j"/");
      }
      else{
       print >> ("splitted/sub"j"/"x);
       close("splitted/sub"j"/"x);
      }

     }' wiki_parsed.xml

【讨论】:

    【解决方案2】:

    简单的答案是调用 close 的频率不够高。以下是说明原因的示例:

    使用如下输入文件:

    <doc somestuff
    another line
    yet another line
    <doc the second
    still more data
    <doc the third
    <doc the fourth
    <doc the fifth
    

    我可以根据您的脚本制作一个可执行的 awk 文件,例如:

    #!/usr/bin/awk -f
    
    BEGIN { system_(++j) }
    
    /<doc/{x=++i}
    
    {
        if (i%5==0 ){ ++i; close_(j"/"x); system_(++j) }
        else{ open_(j"/"x) }
    }
    
    function call_f(funcname, arg) { print funcname"("arg")" }
    
    function system_(cnt) { call_f( "system", cnt ) }
    function open_(f) { if( !(f in a) ) { call_f( "open", f ); a[f]++ } }
    function close_(f) { call_f( "close", f ) }
    

    如果我将其放入一个名为 awko 的文件中,则可以像 awko data 一样运行以生成以下内容:

    system(1)
    open(1/1)
    open(1/2)
    open(1/3)
    open(1/4)
    close(1/5)
    system(2)
    

    我编写的脚本只是通过使用带有尾随_ 的本地函数来隐藏实际函数调用来指示您调用每个函数的次数。请注意,对于相同的参数,open()close() 相比打印了多少次。此外,我最终将 print &gt; 重命名为 open_ 只是为了说明这是打开文件的内容(每个文件名一次)。

    如果我将可执行的 awk 文件更改为以下内容,您可以看到 close 被调用了:

    #!/usr/bin/awk -f
    
    BEGIN { system_(++j) }
    
    /<doc/{ close_(j"/"x); x=++i } # close_() call is moved to here.
    
    {
        if (i%5==0 ){ ++i; system_(++j) }
        else{ open_(j"/"x) }
    }
    
    function call_f(funcname, arg) { print funcname"("arg")" }
    
    function system_(cnt) { call_f( "system", cnt ) }
    function open_(f) { if( !(f in a) ) { call_f( "open", f ); a[f]++ } }
    function close_(f) { call_f( "close", f ) }
    

    给出以下输出:

    system(1)
    close(1/)
    open(1/1)
    close(1/1)
    open(1/2)
    close(1/2)
    open(1/3)
    close(1/3)
    open(1/4)
    close(1/4)
    system(2)
    

    应该清楚的是,close() 被调用的次数已经够多了。第一次在不存在的文件上调用它。对于真正的close() 调用,应该忽略从未打印过此类文件的事实,并且不会尝试实际关闭。在其他情况下,最后一个 open() 匹配 close() 调用。

    像第二个示例脚本一样在脚本中移动您的 close() 调用应该可以解决您的错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-15
      • 2014-10-03
      • 2010-12-07
      • 1970-01-01
      • 2016-03-17
      • 1970-01-01
      相关资源
      最近更新 更多