我有以下 JSON 数据:
{ "姓名": "无人回复", “电子邮件”: ”[电子邮件受保护]“, “ID”:5930, “细节”: { "message": "您的姓名: john doe\n电子邮件:[电子邮件受保护]\n主题:我需要这方面的帮助\n描述:我可以找到手册的下载,但只能找到适用于 Windows 或 Mac 的免费更新程序。你能帮我吗,因为我有一台 Chrome 笔记本电脑和 Moto 智能手机。谢谢。约翰·多伊” } }
顶层的姓名和电子邮件字段是不相关的,因为它们来自自动电子邮件。我需要的信息在消息字段和ID字段中,该字段与John Doe的信息相关。
无论如何,这就是我需要过滤的内容以及如何将其按以下顺序保存到新文件中:
- 姓名:无论文本如何,它都应该读取该变量后面的行。
- 电子邮件:与上面相同
- 主题:与上面相同
- 描述:与上面相同
- ID:与上面相同
因此,我需要删除引号、换行符,通过 bash 将这些特定字符串分配给变量,并读取这些字符串后面的内容。
我能够想出一些东西,但它不适用于此 JSON 输出:(仅当文本文件格式正确时才有效)
while IFS=''
do case "$line" in
"Name:"*) uservar="${line#*: }" ;;
"Email:"*) emailvar="${line#*: }" ;;
"Subject:"*) subject="${line#*: }" ;;
"Message:"*) message="${line#*: }" ;;
"ID:"*) ticketidvar="${line#*: }" ;;
esac
done <<-EOF
$(pbpaste)
EOF
答案1
这假设Description: ...
消息的一部分是单行,并且标头采用规范形式(请不要" subJECT :hey"
)。
它使用 的jq
格式@sh
规范以适合 shell 的方式转义其输出(带单引号)。感谢@Stéphane Chazelas 的更正。
parse_json(){
jq=$(jq -r '[.Email,.ID,(.details.message | split("\n")) | @sh] | join(" ")' -- "$1")
eval "set -- $jq"
email=$1; shift
id=$1; shift
for l; do
case $l in
"Your name: "*) name="${l#*: }";;
"Subject: "*) subject="${l#*: }";;
"Description: "*) description="${l#*: }";;
# remove the following line if you want the .Email from json instead
"Email: "*) email="${l#*: }";;
esac
done
echo "id={$id}"
echo "name={$name}"
echo "email={$email}"
echo "subject={$subject}"
echo "description={$description}"
}
fz:/tmp% parse_json a.json
id={5930}
name={john doe}
email={[email protected]}
subject={I need help with this}
description={I can find the download for the manual but I can only find the free updater for Windows or Mac. Can you help me please as I have a chrome notebook and Moto smart phone. Thank you. John doe
上面case ... esac
的内容可以替换为创建与标题同名的变量,并将非字母数字字符替换为下划线。这仅适用于支持${var//pat/repl}
替换(bash
, zsh
, ksh93
)的 shell:
parse_json(){
jq=$(jq -r '[.Email,.ID,(.details.message | split("\n")) | @sh] | join(" ")' -- "$1")
eval "set -- $jq"
Email=$1; shift
ID=$1; shift
for l; do
v="${l#*: }"; k="${l%%: *}"; eval "${k//[!a-zA-Z0-9]/_}=\$v"
done
}
show_vars(){
for v in ID Your_name Email Subject Description; do
eval "echo \"$v=[\$$v]\""
done
}
fz:/tmp$ parse_json a.json
fz:/tmp$ show_vars
ID=[5930]
Your_name=[john doe]
Email=[[email protected]]
Subject=[I need help with this]
Description=[I can find the download for the manual but I can only find the free updater for Windows or Mac. Can you help me please as I have a chrome notebook and Moto smart phone. Thank you. John doe]
答案2
您可以使用关联数组:
typeset -A field="($(jq -r '
"[ID]=" + (.ID|@sh),
(.details.message|capture("(?m)^(?<t>.*?): (?<v>.*)"; "g")|
"["+(.t|@sh)+"]="+(.v|@sh))' file.json))"
然后您的 ID 位于 ${field[ID]}
,主题位于${field[Subject]}
...
在您的样本上,typeset -p field
输出:
declare -A fields=(
[Description]="I can find the download for the manual but I can only find the free updater for Windows or Mac. Can you help me please as I have a chrome notebook and Moto smart phone. Thank you. John doe"
[ID]="5930"
[Subject]="I need help with this"
[Email]="[email protected]"
["Your name"]="john doe"
)
答案3
我不确定我是否正确理解了您的意思,但如果目的是从 的内容中创建变量,.details.message
我会建议以下内容。
首先.details.message
以原始模式提取jq
:
jq -r '.details.message' in.json
现在解析它,sed
使其可被 bash 解析:
解析.sed
/^Your name: / s//uservar="/
/^Email: / s//emailvar="/
/^Subject: / s//subject="/
/^Description: / s//message="/
s/$/"/
现在您可以在脚本中获取它,例如:
. <(jq -r '.details.message' in.json | sed -f parse.sed)
echo $uservar, $emailvar
输出:
john doe, [email protected]
答案4
假设您需要的只是解码后的.details.message
字符串,后跟带有 ID 的行:
jq -r '.details.message, "ID: \(.ID)"' file >outfile
这将解码.details.message
字符串并添加一个单独的行,其中包含顶级.ID
键的值,前缀为ID:
。
对于给定的 JSON 文档,这将在文件中生成以下输出outfile
:
Your name: john doe
Email: [email protected]
Subject: I need help with this
Description: I can find the download for the manual but I can only find the free updater for Windows or Mac. Can you help me please as I have a chrome notebook and Moto smart phone. Thank you. John doe
ID: 5930