Unix 从键值对中提取值并转换为CSV

Unix 从键值对中提取值并转换为CSV,unix,awk,sed,export-to-csv,key-value,Unix,Awk,Sed,Export To Csv,Key Value,我有以下数据集 data:[{'name': 'cable', 'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'} {'name': 'samsung', 'status': 'none'}], location:[{'place': 'chennai', 'distance': '100km'}, {'place': 'bangalore', 'distance': '200km'

我有以下数据集

data:[{'name': 'cable',  'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'}
{'name': 'samsung',  'status': 'none'}],       location:[{'place': 'chennai', 'distance': '100km'}, 
{'place': 'bangalore', 'distance': '200km'}]
我正在尝试提取值并将其转换为CSV。我在转换为多维数组时遇到问题。任何建议都会有帮助

如果我的数据只是
{'name':'cable','status':'none'},{'name':'laptop','status':'loaded','mode':'high'}
,我可以通过awk使用下面的

awk -F " = " -v OFS="," '
    BEGIN { print "name","status","mode","place","distance" }
    function printline() {
        print data["name"], data["status"], data["mode"]
    }
    {data[$1] = $2}
    NF == 0 {printline(); delete data}
    END {printline()}
'
但是我无法用我的原始数据集

data:[{'name': 'cable',  'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'}
{'name': 'samsung',  'status': 'none'}],       location:[{'place': 'chennai', 'distance': '100km'}, 
{'place': 'bangalore', 'distance': '200km'}]
原始数据

data:[{'name': 'cable',  'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'}
{'name': 'samsung',  'status': 'none'}],       location:[{'place': 'chennai', 'distance': '100km'}, 
{'place': 'bangalore', 'distance': '200km'}]
预期结果

name        status       mode        place       distance
cable       none         null        chennai     100km  
laptop      loaded       high        bangalore   200km 
samsung     none         null        null        null 

以下是在所有UNIX设备上的任意shell中使用任意awk的逐步方法的开始:

$ cat tst.awk
{ rec = (NR>1 ? rec " " : "") $0 }
END {
    # Identify from rec:
    #   1) [{'name': 'cable',  'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'} {'name': 'samsung',  'status': 'none'}]
    #   2) [{'place': 'chennai', 'distance': '100km'}, {'place': 'bangalore', 'distance': '200km'}]

    str = rec
    while ( match(str,/\[[^]]+/) ) {
        val = substr(str,RSTART+1,RLENGTH-1)
        level1vals[++numLevel1vals] = val
        str = substr(str,RSTART+RLENGTH)
    }

    for (level1valNr=1; level1valNr<=numLevel1vals; level1valNr++) {
        level1val = level1vals[level1valNr]

        # Identify from level1vals[1]:
        #   1) 'name': 'cable',  'status': 'none'
        #   2) 'name': 'laptop', 'status': 'loaded', 'mode': 'high'
        #   3) 'name': 'samsung',  'status': 'none'
        # and from level1vals[2]:
        #   4) 'place': 'chennai', 'distance': '100km'
        #   5) 'place': 'bangalore', 'distance': '200km'

        level2valNr = 0
        str = level1val
        while ( match(str,/{[^}]+/) ) {
            val = substr(str,RSTART+1,RLENGTH-1)
            ++level2valNr
            level2vals[level2valNr] = level2vals[level2valNr] " " val
            numLevel2vals = (level2valNr > numLevel2vals ? level2valNr : numLevel2vals)
            str = substr(str,RSTART+RLENGTH)
        }
    }

    # NOTE: delete these print loops when done testing/debugging
    for (level1valNr=1; level1valNr<=numLevel1vals; level1valNr++) {
        print "level1vals[" level1valNr "] = <" level1vals[level1valNr] ">"
    }
    print ""
    for (level2valNr=1; level2valNr<=numLevel2vals; level2valNr++) {
        print "level2vals[" level2valNr "] = <" level2vals[level2valNr] ">"
    }
}
$cat tst.awk
{rec=(NR>1?rec”“:”“)$0}
结束{
#从rec中识别:
#1)[{'name':'cable','status':'none'},{'name':'laptop','status':'loaded','mode':'high'}{'name':'samsung','status':'none'}]
#2)[{'place':'chennai','distance':'100km'},{'place':'bangalore','distance':'200km'}]
str=rec
while(匹配(str,/\[^]]+/){
val=substr(str,RSTART+1,RLENGTH-1)
级别1VAL[++numlevel1VAL]=val
str=substr(str,RSTART+RLENGTH)
}
对于(level1valNr=1;level1valNr numLevel2vals?level2valNr:numLevel2vals)
str=substr(str,RSTART+RLENGTH)
}
}
#注意:完成测试/调试后删除这些打印循环
对于(level1valNr=1;level1valNr)
level2vals[2]=<“名称”:“笔记本电脑”,“状态”:“已加载”,“模式”:“高”“位置”:“班加罗尔”,“距离”:“200公里”>
level2vals[3]=<“名称”:“三星”,“状态”:“无”>

使用
match($0,/\047[^\047]+/)
添加另一轮循环,以识别每个
'foo'
字符串,存储在一个数组中,然后以适当的顺序循环最后一个数组以打印CSV。

下面是一个bash/perl脚本,用于将原始数据转换为“预期结果”格式。要以CSV格式生成结果,只需将
$DLMTR=“\t”
更改为
$DLMTR=“,”


在猜测输入时,我是正确的吗?<代码> JSON < /代码>,如果不是使用SED/AWKI,我的系统中没有安装JQ,也不可能完成。如果使用UNIX命令行,你没有一个解决方案,你没有<代码> JQ < /代码>,然后使用<代码> PHP<代码>或<代码> Perl 或<代码> Python ,甚至<代码> JavaScript < /C> > PAR。使用此JSON字符串并获取CSV数据。BASH中的JSON解析器将状态更改为Loaded如果我不知道我拥有的级别数,我该如何实现?这取决于你的意思,但通常是递归下降算法或循环。编辑你的问题以澄清你的需求,并提供一个更具代表性的示例。我们可以这样做吗没有硬编码代码中的键名称吗?如果给出更多示例数据和用例,则肯定可以使用通用名称(变量类型)代替硬编码名称。
% cat data.txt

data:[{'name': 'cable',  'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'}
{'name': 'samsung',  'status': 'none'}],       location:[{'place': 'chennai', 'distance': '100km'},
{'place': 'bangalore', 'distance': '200km'}]


% cat transform_data.sh

#!/usr/bin/bash

cat $* | tr "," "\n" | perl -lne '
BEGIN {
$i=$j=$data=$location=0;
# Change $DLMTR (delimiter) from "\t" (Tab) to "," for CSV format
$DLMTR="\t"
}

if (/data:/) {$data=1};
if (/location:/) {$location = 1; $data = 0;};

if ($data) { # process elements within data:[]
# \047 = single-quote and change to \042 if double-quote is required
$i++ if /\{/;
/\047name\047:/ && do { $name[$i]=$status[$i]=$mode[$i]=$place[$i]=$distance[$i]="null";
                        ($name[$i])=/:\s*\047(.+?)\047/};
/\047status\047:/ && do {($status[$i])=/:\s*\047(.+?)\047/};
/\047mode\047:/ && do {($mode[$i])=/:\s*\047(.+?)\047/};
}

elsif ($location) { # process elements within location:[]
$j++ if /\{/;
/\047place\047:/ && do {($place[$j])=/:\s*\047(.+?)\047/};
/\047distance\047:/ && do {($distance[$j])=/:\s*\047(.+?)\047/;};
}

END {
print "name${DLMTR}status${DLMTR}mode${DLMTR}place${DLMTR}distance";
foreach $n (1..$i) {
  print "$name[$n]${DLMTR}$status[$n]${DLMTR}$mode[$n]${DLMTR}$place[$n]${DLMTR}$distance[$n]";
}}'


% transform_data.sh data.txt

name        status  mode    place   distance
cable       none    null    chennai 100km
laptop      loaded  high    bangalore       200km
samsung     none    null    null    null