Awk Bash命令/脚本在某个字符上拆分行

Awk Bash命令/脚本在某个字符上拆分行,awk,sed,Awk,Sed,我想将以下数据拆分为预期输出: 原始数据: 931096|376601|1|ART|AT-2151780724|2151780724|2|102809198|I|CGM44I|MIL3VF03|52576377.3600|PENDING|MO|PEND-INFO|Pend ACS4R|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|system|NULL|NULL|52576377.3600|13

我想将以下数据拆分为预期输出:

原始数据:

931096|376601|1|ART|AT-2151780724|2151780724|2|102809198|I|CGM44I|MIL3VF03|52576377.3600|PENDING|MO|PEND-INFO|Pend ACS4R|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|system|NULL|NULL|52576377.3600|1317720|system|2020-02-13 02:00:42|0
931097|375789|1|AYT|AT-2151509210|2151509210|7|102614605|A|CTHGMI|OZF19|444006.6400|APPROVED|NULL|APPROVED|Approved|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|kg17718|NULL|NULL|0.0000|1317722|system|2020-02-13 02:00:43|0931098|375979|1|AHT|AT-2151780726|2151780726|2|102809199|I|CGMI|MILaesLF11|26312.0000|PENDING|MO|PEND-INFO|Pend ACRES|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|system|NULL|NULL|26312.0000|1317721|system|2020-02-13 02:00:43|0
931099|376572|1|AT|AT-2151399812|2151399812|5|102673999|I|CG2rMI|WEL44LF15|60991.6956|PENDING|MO|PEND-INFO|Pend ACERS|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|system|NULL|NULL|0.0000|1317723|system|2020-02-13 02:00:45|0
预期产出:

931096|376601|1|ART|AT-2151780724|2151780724|2|102809198|I|CGM44I|MIL3VF03|52576377.3600|PENDING|MO|PEND-INFO|Pend ACS4R|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|system|NULL|NULL|52576377.3600|1317720|system|2020-02-13 02:00:42|0
931097|375789|1|AYT|AT-2151509210|2151509210|7|102614605|A|CTHGMI|OZF19|444006.6400|APPROVED|NULL|APPROVED|Approved|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|kg17718|NULL|NULL|0.0000|1317722|system|2020-02-13 02:00:43|0
931098|375979|1|AHT|AT-2151780726|2151780726|2|102809199|I|CGMI|MILaesLF11|26312.0000|PENDING|MO|PEND-INFO|Pend ACRES|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|system|NULL|NULL|26312.0000|1317721|system|2020-02-13 02:00:43|0
931099|376572|1|AT|AT-2151399812|2151399812|5|102673999|I|CG2rMI|WEL44LF15|60991.6956|PENDING|MO|PEND-INFO|Pend ACERS|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|system|NULL|NULL|0.0000|1317723|system|2020-02-13 02:00:45|0
基本上\n字符有时会在数据中丢失,行会合并。有时也会有多行合并(甚至相反的情况也会发生,但我们可以稍后再讨论)

数据始终有43列分隔。最后一列(第42列)始终是时间戳,最后一列通常为0或1

尝试以下方法: 如果cols>43 拆分第44列以添加\n并打印剩余列。 重复该过程,直到cols=43


echo“${curr}”|awk-F\|{if(NF>43){for(i=43;i请您尝试使用显示的示例编写并测试以下内容。此解决方案将负责插入新行,即使您的单行中也出现了超过1次

awk '
match($0,/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\|0/){
  val=substr($0,RSTART+RLENGTH)
  if(val){
    num=gsub(/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\|0/,"&")
    while(++count<num){
      sub(/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\|0/,"&\n")
    }
  }
  val=count=num=""
}
1
'  Input_file
awk'
匹配($0,/[0-9]{4}-[0-9]{2}-[0-9]{2}[0-9]{2}:[0-9]{2}:[0-9]{2}\\ 0/){
val=substr($0,RSTART+RLENGTH)
if(val){
num=gsub(/[0-9]{4}-[0-9]{2}-[0-9]{2}[0-9]{2}:[0-9]{2}:[0-9]{2}\\ 0/,“&”)

而(++count使用sed的常用方法是:编写一个正则表达式,将43个字符与介于和数字之间的任何字符进行匹配。然后在匹配的字符串后插入一个换行符

sed 's/[0-9]\{6\}\(|[^|]*\)\{41\}|[0-9]/&\n/g ; s/\n$//'
#                                               ^^^^^^^ - remove the leftover newline
#                                       ^ - the matched string
#                                 ^^^^^ - trailing digit
#                                ^ - 42th pipe character
#                ^^^^^^^^^^^^^^^^ - 41 fields with anything in between
#      ^^^^^^^^^^ - leading 6 digits

或者将42根管子与前面的任何东西和一个数字匹配:

sed 's/\([^|]*|\)\{42\}[0-9]/&\n/g ; s/\n$//'
或在42个管道和数字后匹配字符,并在以下之间插入新行:

sed 's/\(\([^|]*|\)\{42\}[0-9]\)\(.\)/\1\n\3/g'
不太复杂

awk 'BEGIN {FS=OFS="|"} 
     NF>43 {for(i=43;i<=NF;i+=42) {t=$i; $i=substr(t,1,1) ORS substr(t,2)}}1' file

931096|376601|1|ART|AT-2151780724|2151780724|2|102809198|I|CGM44I|MIL3VF03|52576377.3600|PENDING|MO|PEND-INFO|Pend ACS4R|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|system|NULL|NULL|52576377.3600|1317720|system|2020-02-13 02:00:42|0
931097|375789|1|AYT|AT-2151509210|2151509210|7|102614605|A|CTHGMI|OZF19|444006.6400|APPROVED|NULL|APPROVED|Approved|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|kg17718|NULL|NULL|0.0000|1317722|system|2020-02-13 02:00:43|0
931098|375979|1|AHT|AT-2151780726|2151780726|2|102809199|I|CGMI|MILaesLF11|26312.0000|PENDING|MO|PEND-INFO|Pend ACRES|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|system|NULL|NULL|26312.0000|1317721|system|2020-02-13 02:00:43|0
931099|376572|1|AT|AT-2151399812|2151399812|5|102673999|I|CG2rMI|WEL44LF15|60991.6956|PENDING|MO|PEND-INFO|Pend ACERS|N|N|N|N|N|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|N|NULL|NULL|N|system|NULL|NULL|0.0000|1317723|system|2020-02-13 02:00:45|0
awk'BEGIN{FS=OFS=“|”}

NF>43{for(i=43;i您不信任数据源。可能会添加另一个
|
,列数错误。
另一种方法是猜测您可以信任时间戳字段。
因此,当时间戳后的字段包含多个字符时,尝试拆分行(并在第一个字符后拆分)

这可能适用于您(GNU-sed):


如果有第44个字段,请在其前面插入一个换行符。然后删除该换行符,并在第43个字段的第一个字符后面插入。打印第一行,删除第一行,然后重复。

什么意思“换行符有时会丢失”?如果您的计算机、磁盘和网络无法正确存储/处理数据,则没有必要纠正它-它肯定会再次丢失?使用
sed
的通常方法是:编写一个正则表达式,将43个
字符与介于两者之间的任何字符和数字进行匹配。然后在匹配的字符串后插入一个新行。@MarkSetc该死的,我们从另一个来源获得数据,他们无法更正数据,所以我们必须在处理它之前进行更正。@KamilCuk尝试了类似这样的
echo“${curr}”| awk-F\|{if(NF>43){for(i=43;i@vinaykumar,请添加您的努力(您在之前的评论中显示)在你的问题中,作为一种好的做法,注释不是针对同一行的,顺便说一句,感谢你以代码的形式展示了你的努力。这对给定的数据有效,但是如果有一行合并到同一行,那么运行两次会以错误的方式拆分它。如果可以的话,请解释一下你在那里做什么?有一行是空白的ting在最后介绍了。因此在此之后通过
sed-i'/^$/d'文件运行它
sed -E 's/([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\|.)(.)/\1\n\2/g' file
sed 's/[^|]*/\n&/44;s/\(|.\)\([^|]*|\)\n/\1\n\2/;P;D' file