如何在Bash中解析输入

huangapple go评论62阅读模式
英文:

How to parse an input in Bash

问题

test_performance,10.50.100.82,78BAY08V2A/10
test_performance,10.50.100.82,GH7AK1A02097/10
test_1,10.50.101.84,8K251FDD4000D1/13
test_1,10.50.101.84,99071JEGR10369/12

英文:

I am new to Bash and have an input file.log with the following contents:

ok: [test_performance=10.50.100.82] => {
    "msg": [
        [
            "DeviceName:78BAY08V2A/10",
            "DeviceName:GH7AK1A02097/10"
]]}
ok: [test_1=10.50.101.84] => {
    "msg": [
        [
            "DeviceName:8K251FDD4000D1/13",
            "DeviceName:99071JEGR10369/12"
]]}

I want to get output as below:

test_performance,10.50.100.82,78BAY08V2A/10
test_performance,10.50.100.82,GH7AK1A02097/10
test_1,10.50.101.84,8K251FDD4000D1/13
test_1,10.50.101.84,99071JEGR10369/12

I tried below command but it is not working. What can I try next?

grep -C 3 "DeviceName:" file.log | xargs | sed 's/ok/\n/g' | sed 's|[]{}[]||g' | sed 's/msg//g' | sed 's/ =>/,/g' | awk -F ":" '{print $4,$5}' | awk -F "--" '{print $1}' | sed 's/,    /,/g' | sed 's/, /-/g' | sed 's/ //g' | grep -E 'arda|kobra|pipeline|performance|integration|feature|kare|yjr' | sed 's/=/,/g' | sed 's/\(.*\)-/,/' | sed 's/-/,/g' | tee -a file2.csv

答案1

得分: 2

使用GNU awk,使用":=][作为字段分隔符:

awk -F '[":=\\]\\[]' '/^ok/{ok=$3 "," $4} /DeviceName/{print ok "," $3}' file.log

输出:

test_performance,10.50.100.82,78BAY08V2A/10
test_performance,10.50.100.82,GH7AK1A02097/10
test_1,10.50.101.84,8K251FDD4000D1/13
test_1,10.50.101.84,99071JEGR10369/12
英文:

With GNU awk use ", :, =, ] and [ as field separators:

awk -F '[":=\\]\\[]' '/^ok/{ok=$3 "," $4} /DeviceName/{print ok "," $3}' file.log

Output:
<pre>
test_performance,10.50.100.82,78BAY08V2A/10
test_performance,10.50.100.82,GH7AK1A02097/10
test_1,10.50.101.84,8K251FDD4000D1/13
test_1,10.50.101.84,99071JEGR10369/12
</pre>

答案2

得分: 1

使用您提供的示例,请尝试以下GNU awk代码。它将选择从ok:}的行,并根据要求处理它们。

awk -v RS='(^|\n)ok: \\[[^}]*' '
RT{
  match(RT,/ok: \[([^=]*)=([^]]*)\]/,arr)
  val=arr[1]","arr[2]
  while(match(RT,"DeviceName:([^\"]*)",arr)){
    print val","arr[1]
    RT=substr(RT,RSTART+RLENGTH)
  }
}
' Input_file

请注意,这只是翻译的代码部分。如果您需要进一步的解释或帮助,请提出具体问题。

英文:

With your shown samples please try following awk code, written and tested in GNU awk. This will pick up lines from ok: to till } and process them as per requirement.

awk -v RS=&#39;(^|\n)ok: \\[[^}]*&#39; &#39;
RT{
  match(RT,/ok: \[([^=]*)=([^]]*)\]/,arr)
  val=arr[1]&quot;,&quot;arr[2]
  while(match(RT,/&quot;DeviceName:([^&quot;]*)&quot;/,arr)){
    print val&quot;,&quot;arr[1]
    RT=substr(RT,RSTART+RLENGTH)
  }
}
&#39; Input_file

答案3

得分: 1

以下是已翻译的部分:

输入看起来像是以ok: [test_performance=10.50.100.82] =&gt;这样的标签为前缀的JSON对象列表。因此,解析的任务可以分为两个部分:

  1. 解析前缀。
  2. 解析JSON对象。

第一部分看起来不像是一个众所周知的格式,所以我会使用awk、perl或sed来解析它。对于JSON部分,有一个流行的工具叫做jq

以下是使用sedjq的可能解决方案之一:

sed -e &#39;s/\(^ok: .* =&gt; \){/&quot;&quot;:{/;
    1{s/^/{/};
    ${s/$/}/};
    2~1{s/&quot;ok:/,&quot;ok:/}
&#39; file.log | jq --raw-output -e &#39;.|to_entries|.[]|. as $p|.[]
    |$p.value.msg|.[]|.[]
    |sub(&quot;^DeviceName:&quot;;&quot;&quot;) as $d
    |$p.key|capture(&quot;ok: \\[(?&lt;test&gt;.*)=(?&lt;ip&gt;.*)\\]&quot;)
    |.test+&quot;,&quot;+.ip+&quot;,&quot;+$d&#39;

其中,sed命令将整个输入转化为一个JSON对象。它会:

  • 在第一行之前添加大括号(1{s/^/{/})
  • 在最后一行之后添加大括号(${s/$/}/})
  • 用双引号包围“ok:...”前缀。

然后,结果的JSON对象被传递给jq命令。关于其余部分,我建议读者查阅文档:

  • man sed
  • man jq

选择合适的工具

虽然从技术上讲,可以使用awk、sed甚至bash来解析JSON,但我们应该避免这样做,因为这些是通用工具。实现正确的解析器需要一个遵循整个JSON规范的程序。

类似地,生成CSV数据实际上需要专门编写用于此目的的软件。因此,个人而言,我不会在生产环境中使用上述命令。一个正确的解决方案涉及使用比bash、awk或sed更强大的编程语言。只要使用适当的库,Perl、PHP或Node.js脚本都是合适的选择。

英文:

The input looks like a list of JSON objects prefixed with labels like ok: [test_performance=10.50.100.82] =&gt;. So the task of parsing can be divided into two parts:

  1. Parsing the prefixes.
  2. Parsing the JSON objects.

The first part doesn't look like a well-known format, so I'd parse it using awk, perl, or sed. For the JSON part, there is a popular jq tool.

Here is one of the possible solutions using sed and jq:

sed -e &#39;s/\(^ok: .* =&gt; \){/&quot;&quot;:{/;
    1{s/^/{/};
    ${s/$/}/};
    2~1{s/&quot;ok:/,&quot;ok:/}
&#39; file.log | jq --raw-output -e &#39;.|to_entries|.[]|. as $p|.[]
    |$p.value.msg|.[]|.[]
    |sub(&quot;^DeviceName:&quot;;&quot;&quot;) as $d
    |$p.key|capture(&quot;ok: \\[(?&lt;test&gt;.*)=(?&lt;ip&gt;.*)\\]&quot;)
    |.test+&quot;,&quot;+.ip+&quot;,&quot;+$d&#39;

Where the sed command makes a JSON object out of the whole input. It

  • Adds curly braces before the first line(1{s/^/{/}) and after the last line(${s/$/}/}).
  • Surrounds the "ok:..." prefixes with double quotes.

Then the resulting JSON object is piped to the jq command. For the rest, I suggest the reader refer to the documentation:

  • man sed
  • man jq.

Choosing the right tool

While it is technically possible to parse JSON with awk, sed, or even bash, we should avoid doing so because these are general-purpose tools. Implementing a correct parser requires a program that adheres to the entire JSON specification.

Similarly, generating CSV data actually requires software specifically written for this purpose. Therefore, personally, I wouldn't use the command above in a production environment. A proper solution involves using a programming language that is more powerful than bash, awk, or sed. Using a Perl, PHP, or Node.js script would be suitable as long as the appropriate libraries are utilized.

答案4

得分: 1

这是一个与被接受的awk答案有些相似的sed脚本处理过程脚本。请注意,env -S是GNU coreutils对env的扩展。

如果一行以ok:开头,则将该行复制到保持缓冲区(h)。

如果一行包含DeviceName:,则将保持缓冲区附加到模式缓冲区(G)。提取、格式化和排序模式缓冲区中现在有两行的三个字段,并打印(s/.../p)结果。

并像这样运行它:

$ ./process file.log
test_performance,10.50.100.82,78BAY08V2A/10
test_performance,10.50.100.82,GH7AK1A02097/10
test_1,10.50.101.84,8K251FDD4000D1/13
test_1,10.50.101.84,99071JEGR10369/12
英文:

Here is a sed script process script somewhat similar to the accepted awk answer. Note env -S is a GNU coreutils extension of env.

If the line starts with ok: copy the line to the hold buffer (h).

If the line contains DeviceName: append the hold buffer to the pattern buffer (G). Extract and format and order the 3 fields of the now two lines in the pattern buffer and print (s/.../p) the result.

#!/usr/bin/env -S sed -E -n -f

/^ok:/ h
/DeviceName:/ {
	G
    s/.*:([^&quot;]*).*\n.*\[([^=]*)=([^]]*).*/,,/p
}

and run it like this:

$ ./process file.log
test_performance,10.50.100.82,78BAY08V2A/10
test_performance,10.50.100.82,GH7AK1A02097/10
test_1,10.50.101.84,8K251FDD4000D1/13
test_1,10.50.101.84,99071JEGR10369/12

答案5

得分: 0

这是一个使用case模式匹配的Bash脚本process

#!/bin/bash

while read -r line
do
    case "$line" in
        ok:*)
            line=${line#*[}
            line=${line%]*}
            field12=${line/=/,}
            ;;
        *DeviceName:*)
            line=${line#*:}
            field3=${line%\"*}
            echo "$field12,$field3"
            ;;
    esac
done

你可以像这样运行它:

$ ./process < file.log
test_performance,10.50.100.82,78BAY08V2A/10
test_performance,10.50.100.82,GH7AK1A02097/10
test_1,10.50.101.84,8K251FDD4000D1/13
test_1,10.50.101.84,99071JEGR10369/12
英文:

Here is a bash script process that uses the magic of case pattern matching:

#!/bin/bash

while read -r line
do
	case &quot;$line&quot; in
		ok:*)
			line=${line#*[}
			line=${line%]*}
			field12=${line/=/,}
			;;
		*DeviceName:*)
			line=${line#*:}
			field3=${line%\&quot;*}
			echo &quot;$field12,$field3&quot;
			;;
	esac
done

and you would run it like this:

$ ./process &lt; file.log
test_performance,10.50.100.82,78BAY08V2A/10
test_performance,10.50.100.82,GH7AK1A02097/10
test_1,10.50.101.84,8K251FDD4000D1/13
test_1,10.50.101.84,99071JEGR10369/12

huangapple
  • 本文由 发表于 2023年6月16日 13:06:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76487094.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定