将每个第n行命令输出分组为CSV格式

时间:2016-09-19 12:02:35

标签: bash csv awk sed

我正在寻找一种解析多行命令输出的方法;将nth行的每个倍数分组并格式化为CSV格式。

$ cat file
ABC
123
62p4-123
DEF
456
62p4-456

我需要在每个3rd行分组的o / p,以及3的倍数,即第3,第6和第9,然后分别以逗号分隔格式分别为第1,第4和第7以及第2,第5和第8 < / p>

ABC,DEF
123,456
62p4-123,62p4-456

这只是一个示例格式,我的实际用例是json o / p,我想使用bash中的工具/实用程序进行格式设置,而且我不需要格式化选项在jq范围内,我用于解析数据。

我在awk awk 'NR % 3 == 0'中找到了几种方式,但我不能对其他行重复这些方法。

编辑: - 我在这里更新从jq返回的实际JSON o / p以获得最有效的解决方案

4496
http://xxx/yyy
/home/build/branches/mmm/file1
4497
http://xxx/yyy/zzz
/home/build/branches/mmm/file1
4498
http://xxx/yyy/zzz
/home/build/branches/mmm/otherfile.c

预期o / p

4496,4497,4498
http://xxx/yyy,http://xxx/yyy/zzz,http://xxx/yyy/zzz
/home/build/branches/mmm/file1,/home/build/branches/mmm/file1,home/build/branches/mmm/otherfile.c

5 个答案:

答案 0 :(得分:4)

这是一种更简单的方法

$ pr -2ts, file

ABC,DEF
123,456
62p4-123,62p4-456

对于另一个输入,将列数更改为3。

$ pr -3ts, file

4496,4497,4498
http://xxx/yyy,http://xxx/yyy/zzz,http://xxx/yyy/zzz
/home/build/branches/mmm/file1,/home/build/branches/mmm/file1,/home/build/branches/mmm/otherfile.c

如果您只知道行数,而不是最终列数,则可以执行此操作

$ pr -$(awk 'END{print NR/3}' file) -ts, file

答案 1 :(得分:2)

你可以使用这个awk:

awk -v OFS=, 'NR<4{a[NR]=$0; next} {i=(NR%3?NR%3:3); a[i] = a[i] OFS $0} 
          END{for(i=1; i<=3; i++) print a[i]}' file

4496,4497,4498
http://xxx/yyy,http://xxx/yyy/zzz,http://xxx/yyy/zzz
/home/build/branches/mmm/file1,/home/build/branches/mmm/file1,/home/build/branches/mmm/otherfile.c

答案 2 :(得分:1)

$ cat ip.txt 
4496
http://xxx/yyy
/home/build/branches/mmm/file1
4497
http://xxx/yyy/zzz
/home/build/branches/mmm/file1
4498
http://xxx/yyy/zzz
/home/build/branches/mmm/otherfile.c

$ perl -lne '$i = ($.-1)%3; $f[$i] .= $f[$i] ? ",$_" : $_; END{print foreach (@f)}' ip.txt 
4496,4497,4498
http://xxx/yyy,http://xxx/yyy/zzz,http://xxx/yyy/zzz
/home/build/branches/mmm/file1,/home/build/branches/mmm/file1,/home/build/branches/mmm/otherfile.c

这是一种替代解决方案,但在性能方面效率低下

$ (sed -n '1~3p' ip.txt ; sed -n '2~3p' ip.txt ; sed -n '3~3p' ip.txt) | pr -ats, -$(echo $(wc -l < ip.txt)/3 | bc)
4496,4497,4498
http://xxx/yyy,http://xxx/yyy/zzz,http://xxx/yyy/zzz
/home/build/branches/mmm/file1,/home/build/branches/mmm/file1,/home/build/branches/mmm/otherfile.c

答案 3 :(得分:1)

行人,纯Bash(≥4)方法,用mapfile读取内存中的整个文件。

#!/bin/bash

n=3

mapfile -t ary < file

for ((i=0;i<n;++i)); do
    for ((j=i;j<${#ary[@]};j+=n)); do
        (( j >= n )) && printf ,
        printf '%s' "${ary[j]}"
    done
    echo
done

这不是非常有效(所以不要将它用于非常大的文件)。

一种变体是在读取文件时建立要输出的行。

#!/bin/bash

n=3
ary=()
linenb=0

while IFS= read -r line; do
    ((linenb>=n)) && ary[linenb%n]+=,
    ary[linenb++%n]+=$line
done < file

printf '%s\n' "${ary[@]}"

同样,这对于非常大的文件来说效率不高(但它是纯粹的Bash!)。

答案 4 :(得分:1)

$ awk '{k=((NR-1)%3)+1} {a[k]=(k in a ? a[k] "," : "") $0} END{for (i=1;i<=3;i++) print a[i]}' file
ABC,DEF
123,456
62p4-123,62p4-456

$ awk '{k=((NR-1)%3)+1} {a[k]=(k in a ? a[k] "," : "") $0} END{for (i=1;i<=3;i++) print a[i]}' file
4496,4497,4498
http://xxx/yyy,http://xxx/yyy/zzz,http://xxx/yyy/zzz
/home/build/branches/mmm/file1,/home/build/branches/mmm/file1,/home/build/branches/mmm/otherfile.c