【问题标题】:Shell script to merge lines separated by blank line用于合并由空行分隔的行的 Shell 脚本
【发布时间】:2012-12-10 20:10:33
【问题描述】:

我有一个巨大的文本文件(500K 行),其中一些行分成多行。我正在尝试使用拆分线获取记录,显示在一行中。当行被拆分时,在下一行的开头之前有一个空行。现在,我正在遍历每一行,在开始时测试字符串 (AAAA|) 以确定它是否是新行,然后与下一行连接。但这似乎需要很多时间,并且想知道是否有更好的方法来做到这一点。此外,有些行被分成多行,每条新记录都以“AAAA|”开头。

输入文件:

AAAA|XXXX|YYYY|ZZZZ|532920-1*TYCO ELECTRONICS AMP#HDR4-2B-320-PSH2-A*CECO COMPONENT EQUIPMENT CO INC#
AAAA|XXXX|2342342|ADFADFS|A80386DX-33*INTEL CORP#
AAAA|SDFASF|234232322|saddfwq|ER412D-5A*TELEDYNE COMPONENTS#M39016/15-088L*QPL-39016#JMACD-5XL*HI-G INC#914S72101-10L*DRI RELAYS INC#M39016/15-082L*QPL-39016#3SBS1412A2*TYCO ELECTRONICS
CORP#

AAAA|XXXXXXX|5675423|XVASD|N74F132D-T*NXP SEMICONDUCTORS#74F132SC*FAIRCHILD SEMICONDUCTOR CORP#N74F132D*NXP SEMICONDUCTORS#MC74F132D*FREESCALE SEMICONDUCTOR INC#N74F132D,602*NXP SEMICONDU
CTORS#

AAAA|SDFASFSAS|23422|DFGAQWEWE|3SBS1411A2*TYCO ELECTRONICS CORP#914S70301-10L*DRI RELAYS INC#M39016/15-081L*QPL-39016#ER412D-26A*TELEDYNE COMPONENTS#JMACD-26XL*HI-G INC#M39016/15-087L*QPL
-39016#

AAAA|SFRQ3|34543534|NSGBSSDF|3SBS1223A2*TYCO ELECTRONICS CORP#914S60301-10L*DRI RELAYS INC#M39016/15-039L*QPL-39016#914S60301-09L*DRI RELAYS INC#M39016/15-051L*QPL-39016#ER412D-18A/S*TE
LEDYNE COMPONENTS#JMAPD-18XL*HI-G INC#

AAAA|ALSKFJ|1SFAE|ASLKFJSLKSAD|11163-164J*PHILIPS COMPONENTS#SEE_DRAWING_11163-164J*ROHM CO LTD#CF1/4L_164J*KOA SPEER ELECTRONICS INC#SEE_DRAWING_11163-164J*PHILIPS COMPONENTS#CF1/4L
U164J*KOA SPEER ELECTRONICS INC#CF1/4-160K-5%*KOA SPEER ELECTRONICS INC#11163-164J*ROHM CO LTD#131-00164-0053*HONEYWELL CROSS REFERENCE#CF1/4CT52A164J*KOA SPEER ELECTRONICS INC#CF1/4CT52R164J*KOA SPEE
R ELECTRONICS INC#||

AAAA|ASDFAA|1ASFSDAS|ASDFSA|MF 55 D 4323 F*KOA SPEER ELECTRONICS INC#2322156X4324*BC COMPONENTS INC#MF1/4DLT52R4323F*KOA SPEER ELECTRONICS INC#2322 156 X 4324*BC COMPONENTS INC#SFR55432K0
1%*BC COMPONENTS INC#CCF-55 4323 F*VISHAY DALE#CCF-554323F*VISHAY DALE#MF1/4DL_4323F*KOA SPEER ELECTRONICS INC#RN55D4323F*MILITARY SPECIFICATIONS#SFR55 432K0 1%*BC COMPONENTS INC#MF55D4323F*KOA SPEER
ELECTRONICS INC#||

【问题讨论】:

  • 谢谢大家,我的问题解决了!

标签: shell sed awk


【解决方案1】:

使用 Perl 保留空行:

perl -ne 'if (!/^$/) { chomp } else { print "\n" } print' input

在加入后使用 Perl 去除黑线:

perl -ne 'if (!/^$/) { chomp } print' input

使用 GNU Sed(在 posix 模式下不处理最后一行):

sed '/^AAAA/{:l N;/\n./{s/\n//;bl}}' input

【讨论】:

  • 感谢 perreal。除了我在问题中没有明确提及的一种情况外,它工作正常。我的数据文件中的某些行被分成多行,在这种情况下,这个解决方案不起作用。我会更新我的问题以包含它。
  • 我注意到另一件事,当我这样做时: grep "AAAA" oldfile|wc -l 然后在新文件上相同,我得到的计数不同。所以这意味着我丢失了一些数据?
  • 它仍然不适用于多条分割线。例如我上面帖子中的第 7 条记录。
  • @Amogh,添加了一些东西,旧的 sed 只适用于 GNU sed
【解决方案2】:

假设只有最后一列被分成多行:

awk -F"|" 'NF>1{if(x)print x;x=""}{x=x $0;}END{print x}' file

【讨论】:

  • 这应该比我的解决方案执行得更好,@Guru,我敢打赌你来自 unix.com
  • @neevek : 你赢了:)
  • -1 如果一行在# 上分割,这将不起作用。例如:AAAA|SDFASF|234232322|saddfwq|ER412D-5ATELEDYNE COMPONENTS#M39016/15-088LQPL-39016#JMACD-5XLHI-G INC#914S72101-10LDRI RELAYS INC#M39016/15-082L*QPL-39016#\n 3SBS1412A2*TYCO ELECTRONICS\nCORP#
  • 谢谢,如果该行被分成多行,如我上面更新的帖子中所示,您能否提出所需的更改?
【解决方案3】:

算法的sed 版本“如果一行不以AAAA| 开头,只需与上一行连接:”:

sed -n '1x;2,${/^AAAA|/{x;s/\n//g;p};/^AAAA|/!H};${x;s/\n//g;p}' your_file.txt

由于所有sed脚本,需要一些解释:

  • -n :不要在脚本末尾打印模式空间。
  • 1x :记住保持空间中的第一行(交换保持和模式空间)。
  • `2,${...} : 用于倒数第二行。
  • /^AAAA|/{x;s/\n//g;p}:如果该行以新记录模式开始,则将新行保存在保持空间中并取回上一行作为保持空间(交换保持和模式空间),从上一个记录中删除换行符并打印它。
  • /^AAAA|/!H :如果该行不以新记录模式开头,则将其附加到保留空间中的上一行。
  • ${x;s/\n//g;p} :对于最后一行,从保留空间中取回数据,删除换行符并打印。

【讨论】:

  • 非常感谢您的解释,它真的很有帮助。
【解决方案4】:

下面的命令慢吗?

awk '!NF{print line; line=""}{line=line$0}' infile

【讨论】:

  • -1 不起作用。将示例中的前三行错误地合并为一个。所有行必须以AAAA| 开头。
  • @dogbane,请撤销那个-1,我根据OP的描述提供解决方案:当行被拆分时,下一行开始前有一个空行。前 4 行应该被连接起来。
  • 不,OP 明确表示Right now, I am looping through each line, testing for string at start (AAAA|) to identify if it is a new line or not
  • 那我必须给OP打-1,他把我弄糊涂了,让我丢了2分。
  • 这不会输出最后一条记录。您需要添加 END{print line} 但在所有其他方面,这是正确的,因为 OP 的要求绝对指定前导 AAAA,阅读不明确的要求是一个坏主意来自样品溶液。所以+1。
【解决方案5】:

这可能对你有用(GNU sed):

sed ':a;$!N;/\nAAAA/{P;D};s/\n//;ta' file

【讨论】:

    【解决方案6】:

    似乎每条记录应该以井号结尾。如果这是真的,那么:

    awk '{printf("%s", $0)} /#$/ {print ""}' filename
    

    【讨论】:

    • 感谢 glenn,但我的数据文件中的所有记录都不以 # 结尾。
    【解决方案7】:

    如果一行不以AAAA| 开头,只需与上一行连接:

    awk 'NR == 1 { previous = $0 }
         NR > 1 && $0 ~  "^AAAA[|]" { print previous; previous = $0 }
         NR > 1 && $0 !~ "^AAAA[|]" { previous = previous $0 }
         END { print previous }' your_file.txt
    

    我们需要将| 放在[] 之间,因为它是扩展正则表达式的特殊字符。

    【讨论】:

      猜你喜欢
      • 2017-02-05
      • 1970-01-01
      • 2019-08-22
      • 1970-01-01
      • 1970-01-01
      • 2013-10-04
      • 1970-01-01
      • 2021-09-06
      • 2016-07-08
      相关资源
      最近更新 更多