【问题标题】:How do I split a file into several files by a multi-character delimiter?如何通过多字符分隔符将文件拆分为多个文件?
【发布时间】:2017-12-16 22:20:32
【问题描述】:

在 Unix 上,不向操作系统添加任何内容(即仅使用 grepawksedcut 等),如何将以下输入拆分为从每个“codeView”行开始的多个文件(例如“_temp1.txt”、“_temp2.​​txt”等)? 请注意,该行可能以多个空格开头。

如果输入来自 API 而不是现有文件怎么办?

. . .
"events" : [ {
"id" : "123456",
"important" : true,
"codeView" : {
  "lines" : [ {
    "fragments" : [ {
      "type" : "NORMAL_CODE",
      "value" : "str = wrapper.getParameter("
    }, {
      "type" : "NORMAL_CODE",
      "value" : ")"
    } ],
    "text" : "str = wrapper.getParameter("motif")"
  } ],
  "nested" : false
},
"probableStartLocationView" : {
  "lines" : [ {
    "fragments" : [ {
      "type" : "STACKTRACE_LINE",
      "value" : "<init>() @ JSONInputData.java:12"
    } ],
    "text" : "<init>() @ JSONInputData.java:92"
  } ],
  "nested" : false
},
"dataView" : {
  "lines" : [ {
    "fragments" : [ {
      "type" : "TAINT_VALUE",
      "value" : "CP"
    } ],
    "text" : "{{#taint}}CP{{/taint}}"
  } ],
  "nested" : false
},
"collapsedEvents" : [ ],
"dupes" : 0
}, {
"id" : "28861,28862",
"important" : false,
"type" : "P2O",
"description" : "String Operations Occurred",
"extraDetails" : null,
          "codeView" : {
  "lines" : [ {
    "fragments" : [ {
      "type" : "TEXT",
      "value" : "Over the following lines of code, blah blah."
    } ],
    "text" : "Over the following lines of code, blah blah."
  } ],
  "nested" : false
},
"probableStartLocationView" : {
  "lines" : [ {
    "fragments" : [ {
      "type" : "STACKTRACE_LINE",
      "value" : "remplaceString() @ O_UtilCaractere.java:234"
    } ],
    "text" : "remplaceString() @ O_UtilCaractere.java:234"
  }, {
    "fragments" : [ {
      "type" : "STACKTRACE_LINE",
      "value" : "replaceString() @ O_UtilCaractere.java:333"
    } ],
    "text" : "replaceString() @ O_UtilCaractere.java:333"
  }, {
    "fragments" : [ {
      "type" : "STACKTRACE_LINE",
      "value" : "creerIncidentPaie() @ Incidents.java:444"
    } ],
    "text" : "creerIncidentPaie() @ Incidents.java:219"
  }, {
    "fragments" : [ {
      "type" : "STACKTRACE_LINE",
      "value" : "repliquerAbsenceIncident() @ Incidents.java:876"
    } ],
    "text" : "repliquerAbsenceIncident() @ IncidentsPaieMgr.java:882"
  } ],
  "nested" : false
},
"dataView" : {
  "lines" : [ {
    "fragments" : [ {
      "type" : "TEXT",
      "value" : "insert into TGE_INCIDENT...4', 'YYYYMMDD'), 'A', '"
    }, {
      "type" : "TAINT_VALUE",
      "value" : "CP"
    }, {
      "type" : "TEXT",
      "value" : "', '', null, 'T', 'ADPTVT', to_date('2013012214..."
    } ],
    "text" : "insert into TGE_INCIDENT...4', 'YYYYMMDD'), 'A', '{{#taint}}CP{{/taint}}', '', null, 'T', 'ADPTVT', to_date('2017062214..."
  } ],
  "nested" : false
}
. . .

【问题讨论】:

    标签: regex bash shell unix awk


    【解决方案1】:

    这将在任何 awk 中稳定运行:

    awk '/"codeView"/{close(out); out="_temp" ++c ".txt"} out!=""{print > out}' file
    

    【讨论】:

    • 您在最后一个 } 之后缺少一个 '。您说“这将在任何 awk 中稳健地工作:”,但它不适用于 macOS BSD awk 或 GNU Awk 4.1.3。
    • 这是我在 GNU Awk 中遇到的错误,在 macOS 和 Linux Mint 下:gawk: cmd. line:1: (FILENAME=file FNR=1) fatal: expression for '>' redirection has null string value
    • 那么你的文件不能以“codeView”行开头。您希望将 pre-codeView 行打印到哪里?还是您希望它们被丢弃?我调整了脚本以暂时删除它们。顺便说一句,该脚本可移植到所有 awks - 没有人需要在具有多个 awk 的多个平台上对其进行测试,无论您在何处执行它,它在所有 awk 中的工作方式都完全相同。
    • 我直接从 OP 中复制,并且 karakfa 的答案在他的答案中最后一个 } 之后缺少的 ' 被放置。
    • 是的,我查看了,_temp.txt 文件包含直到第一个 "codeView" 的内容,可以忽略,但我同意您的评估。我的工作声明的上下文是显示它处理 file 并且在您进行编辑之前没有像您那样出错。我在这两种环境中都进行了测试,因为我在这两种环境中都工作。无论如何,谢谢我总是从你的回答中学到很多东西。
    【解决方案2】:

    试试:

    csplit -f _temp -b %d.tmp file '/codeView/' '{*}'
    

    或者,如果数据来自其他程序:

    my_api | csplit -f _temp -b %d.tmp - '/codeView/' '{*}'
    

    工作原理

    • -f _temp -b %d.tmp

      这两个选项将拆分文件的名称设置为您想要的格式。

    • file

      将此替换为您的输入文件的名称。如果输入来自标准输入,请使用-

    • /codeView/

      这是您要拆分的正则表达式。

    • '{*}'

      这告诉 csplit 不要在第一次匹配时停止,而是继续拆分。

    【讨论】:

      【解决方案3】:

      awk 来救援!

      $ awk '/"codeView"/{c++} {print > ("_temp" (c+0) ".txt")}' file
      

      第一个匹配的标头将位于第 0 个临时文件中。如果密钥有可能出现在内容中,则可能将模式匹配更改为文字匹配$1=="\"codeView\""

      您可以将数据通过管道传输到awk 脚本,而不是从文件中读取。

      如果打开的文件太多,您可能需要在出错之前关闭它们。

      【讨论】:

      • 您应该提到,不加括号输出重定向的右侧是每个 POSIX 未定义的行为,因此这只会在某些 awks 中执行您想要的操作,而且如果您的文件很大,您将得到一个 "由于在执行过程中未关闭输出文件,因此某些 awk 会出现太多打开的文件”错误。它在 GNU awk 中可以正常工作,所以你可以说它是 gawk-only。
      猜你喜欢
      • 2012-07-04
      • 2013-10-30
      • 2014-08-24
      • 2016-08-01
      • 1970-01-01
      • 2011-11-29
      • 1970-01-01
      • 2013-03-03
      • 1970-01-01
      相关资源
      最近更新 更多