将 key=value 块转换为 CSV

将 key=value 块转换为 CSV

我正在尝试将一个文件的内容转置到另一个文件中。

输入文件Test.txt

HLRSN = 3
IMSI = 404212109727229
KIVALUE = A24AD11812232B47688ADBF15CE05CA9
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3

HLRSN = 3
IMSI = 404212109727230
KIVALUE = A24AD11812232B47688ADBF15CE05CB8
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3

HLRSN = 3
IMSI = 404212109727231
KIVALUE = A24AD11812232B47688ADBF15CE05CD6
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3

另一个文本文件中需要的输出:

3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3

答案1

简单地:

awk -v RS= -v OFS=, '{print $3,$6,$9,$12,$15,$18}'

一个空的记录分隔符( RS=) 启用段落模式其中记录由空行序列分隔。在记录内部,应用默认的字段分隔符(记录由空格分隔),因此在每个记录中,我们感兴趣的字段是第 3 个、第 6 个、第 9 个……

我们改变输出字段分隔符为逗号字符 ( OFS=,) 并打印我们感兴趣的字段。

答案2

一个bash办法:

declare -a out

EOF=false
IFS=$'='

until $EOF; do
  read -r skip val || EOF=true
  if [ ! -z "$val" ]
  then
    out+=("${val//[[:space:]]/}")
  else
    tmp="${out[@]}"
    printf '%s\n' "${tmp// /,}"
    out=()
  fi
done < file

这是如何运作的

  • 声明out用于保存输出行的数组,设置变量EOF以跟踪文件末尾,IFS用于输入字段分隔符read
  • 直到我们读取文件末尾,我们读取文件的每一行,将最后一个字段的值设置为变量val
  • if [ ! -z "$val" ]:检查变量的长度是否$val不为零,我们删除 中的空格$val,将其推送到 array out
  • 如果长度$val为零,意味着我们得到空行或文件结尾,我们将数组的所有元素分配out给变量 tmp,然后tmp,我们设计的输出重新编码分隔符替换所有空间变量。
  • 设置out为 null 以进行下一步工作。

另一种更简洁、更简短的解决方案是使用perl

$ perl -F'=' -anle '
    BEGIN { $, = "," }
    push @out,$F[-1] if @F;
    print @{[map {s/\s// && $_} @out]} and @out = ()
        if /^$/ or eof;
' file
3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3

答案3

将以下内容保存到文件中(例如split.awk

BEGIN {
RS="\n\n";
FS="\n";
ORS=",";
}

{
    for (i=1;i<=NF;i++)
    {
        split($i, sf, "= ")
        print sf[2]
    }
    printf "\n"
 }

然后运行:

awk -f split.awk Test.txt

或者将整个命令作为一行运行:

awk 'BEGIN {RS="\n\n";FS="\n";ORS=",";}{for(i=1;i<=NF;i++){split($i, sf, "= ")print sf[2]}printf "\n"}' Test.txt

其工作原理如下:

  • BEGIN块在开始时运行一次,并将记录分隔符 ( RS) 设置为两个换行符,将字段分隔符 ( FS) 设置为单个换行符。输出记录分隔符 ( ORS) 设置为逗号。

  • 然后它循环遍历记录中的每个字段(NF是当前记录中的字段数)并将其拆分为“=”。

  • 然后它打印该分割的右手,每个分割之间有一个逗号(the ORS

  • 每行后面都会打印一个换行符,为您提供 CSV 格式。

答案4

使用磨坊主( mlr) 我们可以将数据读取为由双换行符分隔的记录,其中包含由单换行符分隔的字段,包含由等号分隔的键值对。我们可以删除多余的空格和空列(使用这些分隔符读取数据的结果会在每个字段值的开头引入一个空格),然后将其转换为 CSV:

$ mlr --ips = --ifs lf --irs lflf --ocsv clean-whitespace then remove-empty-columns Test.txt
HLRSN,IMSI,KIVALUE,K4SNO,CARDTYPE,ALG
3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3

如果您不希望输出中包含 CSV 标头,请mlr与其-N选项一起使用。 Miller 将自动引用任何包含嵌入分隔符或引号的字段。

相关内容