如何将文件从 bash 转换为 json

How convert file to json from bash

我有一个像这样的 .file,想把它转换成 JSON 格式。

2022/01/22 21:27:56 [notice] 40#40: signal process started
2022/01/22 21:27:56 [error] 40#40: open() "/run/nginx.pid" failed (2: No such file or directory)
2022/01/22 21:28:04 [notice] 42#42: signal process started
2022/01/22 21:28:04 [error] 42#42: open() "/run/nginx.pid" failed (2: No such file or directory)

代码

#!/bin/bash
json=''
while read -r line; do
    dt=$(echo ${line} | awk '{print (" ")}')
    info=$(echo ${line} | awk '{print ()}')
    error=$(echo ${line} | awk '{print ()}')
    json+="{\"date\":\"$dt\","\"info\":\"$info\",\"error\":\"$error\""}"
done < "$file"
    
res="$json"

如何使 var res 像 JSON 格式一样用逗号分隔符 "," 每个对象 {}


我想这样输出

[{"date":"2022/01/22 21:27:56","info":"[notice]","error":"40#40:signalprocessstarted"},
{"date":"2022/01/22 21:27:56","info":"[error]","error":"40#40:open()"/run/nginx.pid"failed(2:Nosuch"},
{"date":"2022/01/22 21:28:04","info":"[notice]","error":"42#42:signalprocessstarted"},
{"date":"2022/01/22 21:28:04","info":"[error]","error":"42#42:open()"/run/nginx.pid"failed(2:Nosuch"}]

但现在我的输出看起来像这样

{"date":"2022/01/22 21:27:56","info":"[notice]","error":"40#40:signalprocessstarted"}{"date":"2022/01/22 21:27:56","info":"[error]","error":"40#40:open()"/run/nginx.pid"failed(2:Nosuch"}{"date":"2022/01/22 21:28:04","info":"[notice]","error":"42#42:signalprocessstarted"}{"date":"2022/01/22 21:28:04","info":"[error]","error":"42#42:open()"/run/nginx.pid"failed(2:Nosuch"}

对象之间没有任何分隔符

以及如何在 JSON

中处理 "/run/nginx.pid" 这样的字符串

请您尝试以下操作:

#!/bin/bash

echo -n "["
while read -r day hms info err; do              # split on blank characters up to 4 words
    if (( nr++ )); then                         # count the line number
        echo ","                                # append a comma after the previous line
    fi
    err="$(sed -E 's/"/\&/g' <<< "$err")"      # escape double quotes in the message
    printf '{"date":"%s %s","info":"%s","error":"%s"}' "$day" "$hms" "$info" "$err"
done < file
echo "]"

输出:

[{"date":"2022/01/22 21:27:56","info":"[notice]","error":"40#40: signal process started"},
{"date":"2022/01/22 21:27:56","info":"[error]","error":"40#40: open() \"/run/nginx.pid\" failed (2: No such file or directory)"},
{"date":"2022/01/22 21:28:04","info":"[notice]","error":"42#42: signal process started"},
{"date":"2022/01/22 21:28:04","info":"[error]","error":"42#42: open() \"/run/nginx.pid\" failed (2: No such file or directory)"}]

[编辑]
如果要将变量(例如 var)分配给生成的 json 格式的字符串,请将整个代码用 $() 括起来,作为 command substitution 然后将变量赋值给它如:

var=$(
echo -n "["
while read -r day hms info err; do              # split on blank characters up to 4 words
    if (( nr++ )); then                         # count the line number
        echo ","                                # append a comma after the previous line
    fi
    printf '{"date":"%s %s","info":"%s","error":"%s"}' "$day" "$hms" "$info" "${err//\"/\\"}"
                                                # escape double quotes in $err according to Ed Morton's suggestion
done < file
echo "]"
)
echo "$var"                                     # just to see the result

如果有jq也可以说:

echo -n "["
while read -r day hms info err; do              # split on blank characters up to 4 words
    if (( nr++ )); then                         # count the line number
        echo ","                                # append a comma after the previous line
    fi
    jq -cn --arg date "$day $hms" --arg info "$info" --arg error "$err" '{date:$date, info:$info, error:$error}'
done < file
echo "]"

正如戈登戴维森所建议的那样。

请阅读why-is-using-a-shell-loop-to-process-text-considered-bad-practice。发明shell的人也发明了awk供shell调用处理文本

假设您真的不想从每个输入行末尾的消息中截断和删除所有白色 space,并且您希望输入中的所有双引号在输出中转义,您可以这样做这在每个 Unix 机器上的任何 shell 中有效且可移植地使用任何 awk:

$ cat tst.awk
BEGIN {
    printf "["
    ofmt = "%s{\"date\":\"%s %s\",\"info\":\"%s\",\"error\":\"%s\"}"
}
{
    error = [=10=]
    sub(/([^ ]+ ){3}/,"",error)
    gsub(/"/,"\\"",error)
    printf ofmt, sep, , , , error
}
END { print "]" }

$ awk -f tst.awk file
[{"date":"2022/01/22 21:27:56","info":"[notice]","error":"40#40: signal process started"},
{"date":"2022/01/22 21:27:56","info":"[error]","error":"40#40: open() \"/run/nginx.pid\" failed (2: No such file or directory)"},
{"date":"2022/01/22 21:28:04","info":"[notice]","error":"42#42: signal process started"},
{"date":"2022/01/22 21:28:04","info":"[error]","error":"42#42: open() \"/run/nginx.pid\" failed (2: No such file or directory)"}]