linux/bash通过类似json的数据进行解析



以下是我拥有的一些数据:

animal { 
dog {
body {
parts {
legs = old
brain = average
tail= curly
}

}
}
cat {
body {
parts {
legs = new
brain = average
tail {
base=hairy
tip=nothairy
}

}
}
}
}

请注意,数据并不是真正的json,因为它有以下规则:

  • 支持键和值对之间的==
  • 在整个数据中没有",。数据的分离是基于新行的

有可能用awk或sed来解析它吗?我尝试了jq,但它不起作用,因为这不是真正的json数据。

我的目标是只显示";狗;以及";猫";。基于它们是";动物";。

$ some-magical-command
dog
cat

为了完成您当前想要的操作,并便于将来对数据进行任何操作,您可以使用任何POSIXawk(用于字符类(将结构转换为JSON,然后在其上使用jq

$ cat tst.awk
BEGIN { print "{" }
!NF { next }
{
sub(/[[:space:]]+$/,"")
gsub(/[[:alnum:]_]+/,""&"")
gsub(/ *= */,": ")
sub(/" *{/,"": {")
}
(++nr) > 1 {
sep = ( /"/ && (prev ~ /["}]$/) ? "," : "" )
printf "%s%s%s", prev, sep, ORS
}
{ prev = $0 }
END { print prev ORS "}" }

$ awk -f tst.awk file
{
"animal": {
"dog": {
"body": {
"parts": {
"legs": "old",
"brain": "average",
"tail": "curly"
}
}
},
"cat": {
"body": {
"parts": {
"legs": "new",
"brain": "average",
"tail": {
"base": "hairy",
"tip": "nothairy"
}
}
}
}
}
}

当前和一些可能的未来用途:

$ awk -f tst.awk file | jq -r '.animal | keys[]'
cat
dog

$ awk -f tst.awk file | jq -r '.animal.dog.body.parts | keys[]'
brain
legs
tail

$ awk -f tst.awk file | jq -r '.animal.dog.body.parts'
{
"legs": "old",
"brain": "average",
"tail": "curly"
}

$ awk -f tst.awk file | jq -r '.animal.cat.body.parts'
{
"legs": "new",
"brain": "average",
"tail": {
"base": "hairy",
"tip": "nothairy"
}
}

以上假设您的输入始终如问题所示。

如果你想学习一门新语言,它非常接近tcl语法。

set data {
animal { 
dog {
body {
parts {
legs = old
brain = large
tail= curly
}

}
}
cat {
body {
parts {
legs = new
brain = tiny
tail {
base=hairy
tip=nothairy
}

}
}
}
}
}
set data [regsub -line -all {s*=s*(.+)} $data { "1"}]
dict get $data animal dog body parts brain    ;# => large

我知道有些人会争论你对狗大脑和猫大脑的分类。。。

如果您只需要二级键,并且不太关心为错误输入生成良好的错误消息,那么这是非常直接的。基本思想是:

  1. 输入行有三种格式:

    • ID{
    • ID=值#,其中=可能不以空格分隔
    • }
  2. 当读取行时,我们通过用第一行类型递增计数器并用第三行类型递减计数器来跟踪嵌套深度。

  3. 当嵌套计数器为1时,如果该行有一个ID字段,我们将其打印出来

这可以用awk脚本简单地完成。这个脚本应该保存在一个名为level2_keys.awk的文件中;然后可以执行命令CCD_ 10。请注意,所有规则都以next;结尾,以避免评估匹配后的规则。

$1 == "}"    { # Decrement nesting on close
--nesting;
next;
}
/=/          { # Remove the if block if you don't want to print these keys.
if (nesting == 1) {
gsub("=", " = ");    # Force = to be a field
print($1);
}
next;
}
$2 == "{"    { # Increment nesting (and maybe print) on open
if (nesting == 1) print($1);
++nesting;
next;
}
# NF is non-zero if the line is not blank.
NF           { print "Bad input at " NR ": '"$0"'" > "/dev/stderr"; }

最新更新