在Bash中将多行字符串转换为单个逗号分隔的列表

时间:2018-07-11 13:43:02

标签: bash awk sed

我有这种格式:

id  firstmark   secondmark  thirdmark
1   23  23  23
2   23  23  23
3   23  23  23
4   23  23  23
5   23  23  23
6   23  23  23
7   23  23  23
8   23  23  23

我需要这样的格式:

host1,app1
host1,app2
host1,app3
host2,app4
host2,app5
host2,app6
host3,app1
host4... and so on.

我对此感到厌倦:host1;app1,app2,app3 host2;app4,app5,app6  它给了我这个:

awk -vORS=, '{ print $2 }' data | sed 's/,$/\n/',主机不在前面。

我不想显示重复项。

我不想要这样:

app1,app2,app3

我想要这种格式:

host1;app1,app1,app1,app1...
host2;app1,app1,app1,app1...

4 个答案:

答案 0 :(得分:1)

在第一列上对输入进行排序(如您的示例;否则将其通过管道传输到sort),则可以使用以下awk命令:

awk -F, 'NR == 1 { currentHost=$1; currentApps=$2 } 
         NR > 1 && currentHost == $1 { currentApps=currentApps "," $2 }
         NR > 1 && currentHost != $1 { print currentHost ";" currentApps; currentHost=$1; currentApps=$2 }
         END { print currentHost ";" currentApps }'

与本次编辑发布的其他解决方案相比,它具有优势,可以避免将整个数据保存在内存中。这是以需要对输入进行排序为代价的(如果尚未对输入进行排序,这将需要在存储器中放入大量数据)。

说明:

  • 第一行将currentHostcurrentApps变量初始化为输入的第一行的值
  • 第二行处理的主机与上一主机具有相同的主机:该行中提到的应用程序将附加到currentApps变量
  • 第三行处理的主机与上一主机的行不同:打印前一主机的信息,然后将变量重新初始化为当前输入行的值
  • 当我们到达输入的末尾时,最后一行显示当前主机的信息

它可能可以改进(有很多冗余!),但我会将其留给对awk更有经验的人。

See it in action !

答案 1 :(得分:1)

$ awk '
    BEGIN { FS=","; ORS="" }
    $1!=prev { print ors $1; prev=$1; ors=RS; OFS=";" }
    { print OFS $2; OFS=FS }
    END { print ors }
' file
host1;app1,app2,app3
host2;app4,app5,app6
host3;app1

答案 2 :(得分:0)

也许是这样的:

#!/bin/bash  
declare -A hosts
while IFS=, read host app
do
    [ -z "${hosts["$host"]}" ] && hosts["$host"]="$host;"
    hosts["$host"]+=$app,
done < testfile

printf "%s\n" "${hosts[@]%,}" | sort

该脚本从testfile中读取示例数据,并输出到stdout

答案 3 :(得分:0)

您可以尝试以下awk脚本:

awk -F, '{a[$1]=($1 in a?a[$1]",":"")$2}END{for(i in a) printf "%s;%s\n",i,a[i]}' file

脚本为第一列中的每个唯一元素在数组a中创建条目。它将第二列中的所有元素附加到该数组条目。

解析文件后,将打印数组的内容。