如何通过命令行将每三行文本合并为一行?
问题描述
我有一个按特定格式排列的文本文件,需要把每三行合并成一行。试了一些Unix命令,但结果不符合预期。
我用的命令是:
sed -n '/TitanBalance/{ N s/\n/ /p }' Titaninput.txt
文本内容示例:
<TitanBalance releaseID="9999.999" languageCode="en" xmlns="www.titan.com" xmlns:ns="www.titan.org"><ns:ApplicationArea><ns:Sender><ns:LogicalID>ATG</ns:LogicalID><ns:ComponentID>0.0.1.1</ns:ComponentID></ns:Sender><ns:CreationDateTime>2024-05-16T09:26:02.378+02:00</ns:CreationDateTime><ns:DAD>556666660000</ns:DAD></ns:ApplicationArea><DataArea><ns:Process><ns:ActionList><ns:actionFile expressionLanguage="text" actionCode="Modified">supplier</ns:actionFile></ns:ActionList></ns:Process> <suppementaryBalance><ProductItem><ns:ItemID><ns:ID>000000000101090593</ns:ID></ns:ItemID><ns:UOMCode>EA</ns:UOMCode></ProductItem><ns:supplierdQuantity>1</ns:supplierdQuantity><ns:SalesOrderReference><ns:DocumentID><ns:ID>6666666666666</ns:ID></ns:DocumentID><ns:LineNumber>1</ns:LineNumber></ns:SalesOrderReference><companycode>1488</companycode><ns:Type>Standard</ns:Type><FulfilmentSourceType>new arrival</FulfilmentSourceType></suppementaryBalance> </DataArea></TitanBalance> <TitanBalance releaseID="9999.999" languageCode="en" xmlns="www.titan.com" xmlns:ns="www.titan.org"><ns:ApplicationArea><ns:Sender><ns:LogicalID>ATG</ns:LogicalID><ns:ComponentID>0.0.1.1</ns:ComponentID></ns:Sender><ns:CreationDateTime>2024-05-16T09:26:02.378+02:00</ns:CreationDateTime><ns:DAD>556666660000</ns:DAD></ns:ApplicationArea><DataArea><ns:Process><ns:ActionList><ns:actionFile expressionLanguage="text" actionCode="Modified">supplier</ns:actionFile></ns:ActionList></ns:Process> <suppementaryBalance><ProductItem><ns:ItemID><ns:ID>000000000100007893</ns:ID></ns:ItemID><ns:UOMCode>EA</ns:UOMCode></ProductItem><ns:supplierdQuantity>1</ns:supplierdQuantity><ns:SalesOrderReference><ns:DocumentID><ns:ID>88888888888888</ns:ID></ns:DocumentID><ns:LineNumber>3</ns:LineNumber></ns:SalesOrderReference><companycode>1488</companycode><ns:Type>Standard</ns:Type><FulfilmentSourceType>new arrival</FulfilmentSourceType></suppementaryBalance> </DataArea></TitanBalance>
期望输出(每三行XML合并为单行):
<TitanBalance releaseID="9999.999" languageCode="en" xmlns="www.titan.com" xmlns:ns="www.titan.org"><ns:ApplicationArea><ns:Sender><ns:LogicalID>ATG</ns:LogicalID><ns:ComponentID>0.0.1.1</ns:ComponentID></ns:Sender><ns:CreationDateTime>2024-05-16T09:26:02.378+02:00</ns:CreationDateTime><ns:DAD>556666660000</ns:DAD></ns:ApplicationArea><DataArea><ns:Process><ns:ActionList><ns:actionFile expressionLanguage="text" actionCode="Modified">supplier</ns:actionFile></ns:ActionList></ns:Process><suppementaryBalance><ProductItem><ns:ItemID><ns:ID>000000000101090593</ns:ID></ns:ItemID><ns:UOMCode>EA</ns:UOMCode></ProductItem><ns:supplierdQuantity>1</ns:supplierdQuantity><ns:SalesOrderReference><ns:DocumentID><ns:ID>6666666666666</ns:ID></ns:DocumentID><ns:LineNumber>1</ns:LineNumber></ns:SalesOrderReference><companycode>1488</companycode><ns:Type>Standard</ns:Type><FulfilmentSourceType>new arrival</FulfilmentSourceType></suppementaryBalance></DataArea></TitanBalance>
解决方案
方法1:改进sed命令
原sed命令只合并了两行,要实现三行合并并跳过空行,用这个命令:
sed '/^$/d; :a; N; s/\n//; /<\/TitanBalance>/!ba' Titaninput.txt
/^$/d:先删掉所有空行,避免干扰合并:a:定义一个循环标签N:把下一行内容读入当前模式空间s/\n//:将模式空间里的换行符替换为空,实现行合并/<\/TitanBalance>/!ba:如果当前模式空间里没有XML结束标签</TitanBalance>,就跳回标签a继续循环合并,直到凑齐完整的三行XML
方法2:用awk按行数计数合并
awk可以按行号计数,每累计3行就输出合并结果,同时跳过空行:
awk '!/^$/ {line = line $0} NR%3==0 {print line; line=""} END {if(line!="") print line}' Titaninput.txt
!/^$/:跳过空行,不加入合并内容line = line $0:把当前行内容追加到临时变量line中NR%3==0:当处理到第3、6、9...行时,打印合并后的line并清空变量END块:处理文件末尾可能剩下的不足3行的内容(如果有的话)
方法3:用paste快速合并
paste工具支持直接指定合并行数,配合sed清理空行:
paste -d '' - - - < Titaninput.txt | sed '/^$/d'
paste -d '' - - -:每次从输入读取3行,用空字符连接(即直接拼接成一行)sed '/^$/d':删除合并后产生的空行(原文件中的空行被paste处理后会变成空行)
内容的提问来源于stack exchange,提问作者Pandora
相关产品推荐
相关产品推荐

