Bash 如何合并文件中的每n行

Bash 如何合并文件中的每n行,bash,unix,awk,sed,Bash,Unix,Awk,Sed,我试着把类似的几组线连接到一条线上。我的文件是一个基本的日志类型文件,但每个条目跨越三行,后跟一个换行符。例如: Timestamp key1 | val1 | key2 | val2 key3 | val3 | key4 | val4 Timestamp key1 | val1 | key2 | val2 key3 | val3 | key4 | val4 我想要的是,每一块3行都在一行上,以逗号分隔: Timestamp,key1,val1,key2,val2,key3,val3,key

我试着把类似的几组线连接到一条线上。我的文件是一个基本的日志类型文件,但每个条目跨越三行,后跟一个换行符。例如:

Timestamp
key1 | val1 | key2 | val2
key3 | val3 | key4 | val4

Timestamp
key1 | val1 | key2 | val2
key3 | val3 | key4 | val4
我想要的是,每一块3行都在一行上,以逗号分隔:

Timestamp,key1,val1,key2,val2,key3,val3,key4,val4
如果我只需要处理键/值行,我就可以使用sed&awk实现这一点,但我的问题是获取每行的时间戳

我看到的东西正在使用,但它们似乎都没有达到我所需要的效果。

试试:

awk '/^Timestamp/ && VAL{print VAL;VAL=$0;next} {gsub(/ +\| +/,",");VAL=VAL?VAL OFS $0:$0} END{print VAL}' OFS=","   Input_file
查找字符串Timestamp和VAL(如果两者都有值),然后打印变量VAL的值,然后将VAL分配到当前行,并提及下一行以跳过所有其他语句。如果不满足此条件,则用逗号全局替换空格|空格,然后生成一个名为VAL的变量,该变量的值每次都将与其自身的值连接。然后在最后一节也打印VAL的值,因为VAL可能在那里

试试看:

awk '/^Timestamp/ && VAL{print VAL;VAL=$0;next} {gsub(/ +\| +/,",");VAL=VAL?VAL OFS $0:$0} END{print VAL}' OFS=","   Input_file
$ awk -v RS= -F'\n| \\| ' -v OFS=',' '{$1=$1}1' file
Timestamp,key1,val1,key2,val2,key3,val3,key4,val4
Timestamp,key1,val1,key2,val2,key3,val3,key4,val4

查找字符串Timestamp和VAL(如果两者都有值),然后打印变量VAL的值,然后将VAL分配到当前行,并提及下一行以跳过所有其他语句。如果不满足此条件,则用逗号全局替换空格|空格,然后生成一个名为VAL的变量,该变量的值每次都将与其自身的值连接。然后在最后一节也打印VAL的值,因为VAL可能在那里

此awk使用内置RS变量简化记录之间的移动。我们检测是否在时间戳行上,如果在时间戳行上,则设置
ts
变量。然后,由于我们将RS
$1
设置为通过
$NF
将是我们的键、值字段,因此迭代它们并将它们附加到输出字符串中。我们将最后一个保存在循环外部,这样就可以避免出现悬空的
。然后我们只需打印该行并继续

$ awk -v RS= -F'\n| \\| ' -v OFS=',' '{$1=$1}1' file
Timestamp,key1,val1,key2,val2,key3,val3,key4,val4
Timestamp,key1,val1,key2,val2,key3,val3,key4,val4
BEGIN{
    RS="\n\n";  # Everything between blank lines will be treated as one record
    FS="|";     # Our fields are separated with pipes.
}
{ 
    if( NF == 1 ){   # The number of fields on this line is 1... only our timestamp lines look like this.
        ts=$1;      
        next;       # Go to next record.
    };  



    # Build up an output buffer while avoiding dangling ","   
    out="";          

    for( i=1; i < NF; i++ ){
        out=out$i","
    } 

    out=out$NF; 

    print ts","out 
}
开始{
RS=“\n\n”#空行之间的所有内容都将被视为一条记录
FS=“|”;#我们的田地用管道隔开。
}
{ 
如果(NF==1){#这一行上的字段数是1…只有我们的时间戳行是这样的。
ts=$1;
下一张;#转到下一张唱片。
};  
#建立输出缓冲区,同时避免挂起“,”
out=“”;
对于(i=1;i
此awk使用内置RS变量简化记录之间的移动。我们检测是否在时间戳行上,如果在时间戳行上,则设置
ts
变量。然后,由于我们将RS
$1
设置为通过
$NF
将是我们的键、值字段,因此迭代它们并将它们附加到输出字符串中。我们将最后一个保存在循环外部,这样就可以避免出现悬空的
。然后我们只需打印该行并继续

BEGIN{
    RS="\n\n";  # Everything between blank lines will be treated as one record
    FS="|";     # Our fields are separated with pipes.
}
{ 
    if( NF == 1 ){   # The number of fields on this line is 1... only our timestamp lines look like this.
        ts=$1;      
        next;       # Go to next record.
    };  



    # Build up an output buffer while avoiding dangling ","   
    out="";          

    for( i=1; i < NF; i++ ){
        out=out$i","
    } 

    out=out$NF; 

    print ts","out 
}
开始{
RS=“\n\n”#空行之间的所有内容都将被视为一条记录
FS=“|”;#我们的田地用管道隔开。
}
{ 
如果(NF==1){#这一行上的字段数是1…只有我们的时间戳行是这样的。
ts=$1;
下一张;#转到下一张唱片。
};  
#建立输出缓冲区,同时避免挂起“,”
out=“”;
对于(i=1;i
使用
sed
粘贴的替代解决方案

$ sed 's/ *| */,/g;/^$/d' file | paste -d, - - -

Timestamp,key1,val1,key2,val2,key3,val3,key4,val4
Timestamp,key1,val1,key2,val2,key3,val3,key4,val4
读起来像:
用逗号替换分隔符,删除空行,一次粘贴3行,中间使用逗号分隔符。

使用
sed和
粘贴的替代解决方案

$ sed 's/ *| */,/g;/^$/d' file | paste -d, - - -

Timestamp,key1,val1,key2,val2,key3,val3,key4,val4
Timestamp,key1,val1,key2,val2,key3,val3,key4,val4
读起来像:
用逗号替换分隔符,删除空行,一次粘贴3行,中间用逗号分隔符。

一些愚蠢的仅sed技巧:

sed-n-e'/Timestamp/{h;n};s/|/,/g;H/^$/{g;s/\n/,/g;s/,$/;p}文件

  • 使用
    sed-n
    仅在使用
    p
    命令时打印
  • /Timestamp/{h;n}将保留空间替换为时间戳行,并移到下一行输入
  • s/|/,/g;H将条形替换为逗号并附加到保留空间
  • 空行上的
    /^$/{g;s/\n/,/g;s/,$/;p}
    将保留空间的内容放入模式空间,
    s/\n/,/g
    用逗号替换换行符,最后
    s/,$/;p
    删除尾随逗号并打印图案空间
输入
文件

Timestampa
key1 | val1 | key2 | val2
key3 | val3 | key4 | val4

Timestampb
key1 | val1 | key2 | val2
key3 | val3 | key4 | val4
输出:

Timestampa,key1,val1,key2,val2,key3,val3,key4,val4
Timestampb,key1,val1,key2,val2,key3,val3,key4,val4

s/\n/,/g
可能依赖于系统/sed版本。

一些愚蠢的仅sed技巧:

sed-n-e'/Timestamp/{h;n};s/|/,/g;H/^$/{g;s/\n/,/g;s/,$/;p}文件

  • 使用
    sed-n
    仅在使用
    p
    命令时打印
  • /Timestamp/{h;n}将保留空间替换为时间戳行,并移到下一行输入
  • s/|/,/g;H将条形替换为逗号并附加到保留空间
  • 空行上的
    /^$/{g;s/\n/,/g;s/,$/;p}
    将保留空间的内容放入模式空间,
    s/\n/,/g
    用逗号替换换行符,最后
    s/,$/;p
    删除尾随逗号并打印图案空间
输入
文件

Timestampa
key1 | val1 | key2 | val2
key3 | val3 | key4 | val4

Timestampb
key1 | val1 | key2 | val2
key3 | val3 | key4 | val4
输出:

Timestampa,key1,val1,key2,val2,key3,val3,key4,val4
Timestampb,key1,val1,key2,val2,key3,val3,key4,val4
s/\n/,/g
可能与系统/sed版本有关。

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

在模式空间中读入3行,用逗号替换管道或换行符(可能被空格包围),打印成功的替换并丢弃空行。

这可能适合您(GNU-sed):

在模式空间中读3行,用逗号替换管道或换行符(可能被空格包围),打印成功