我正在使用 shell 脚本来更新 JSON。以前我使用 jq 命令来读取/写入 JSON 对象。然而似乎并不是每个 bash 环境都支持 jq 命令。我尝试通过使用 awk、sed 和 gsup 操作字符串来解决这个问题。
但是语法很复杂,如下所示:
update_json_key() {
local key="$1"
local value="$2"
local filename="$3"
if [[ ! -f "$filename" ]]; then
echo "{}" > "$filename"
fi
SED_INPLACE=""
if [[ "$OSTYPE" == "darwin"* ]]; then
SED_INPLACE="-i ''" # macOS requires an empty extension for in-place editing
else
SED_INPLACE="-i" # Linux
fi
# Ensure the file exists and is a valid JSON object
if [ ! -s "$filename" ] || ! grep -q "{" "$filename"; then
echo "{}" > "$filename"
fi
# Check if the key exists
if grep -q "\"$key\": " "$filename"; then
# Key exists, update it
# This regex ensures we don't capture more than we need by being specific with our patterns
sed $SED_INPLACE "s/\"$key\": \"[^\"]*\"/\"$key\": \"$value\"/" "$filename"
else
# Key does not exist, add it
if grep -q "^{}$" "$filename"; then
# File has only empty JSON, directly add key without comma
sed $SED_INPLACE "s/{}/{\"$key\": \"$value\"}/" "$filename"
else
# File is non-empty, append key before the last closing brace
# This ensures that we correctly find the last closing brace even when it's not at the very end
sed $SED_INPLACE "s/\(.*\)}$/\1, \"$key\": \"$value\"}/" "$filename"
fi
fi
if [ -e "$filename''" ]; then
rm -f "$filename''"
fi
if [[ -e "$filename" ]] && [[ $(wc -l < "$filename") -gt 1 ]]; then
raw_json=$(sed -e ':a' -e 'N' -e '$!ba' -e 's/\n//g' -e 's/": \?"/": "/g' -e 's/, \?"/,"/g' "$filename")
rm -f $filename
echo "$raw_json" > "$filename"
fi
formatted_json=$(awk 'BEGIN {
FS=",";
print "{"
}
{
gsub(/[{}]/, "");
n = split($0, a, ",");
for (i = 1; i <= n; i++) {
gsub(/^[[:space:]]+|[[:space:]]+$/, "", a[i]);
print " " a[i] (i < n ? "," : "");
}
}
END {
print "}"
}' "$filename")
rm -f $filename
echo "$formatted_json" > "$filename"
}
此语法尚未处理任何嵌套 JSON 对象迭代。我在想是否有一种更简单的方法可以在不使用 jq 的情况下使用 shell 脚本操作 JSON 对象。
似乎不是每个 bash 环境都支持 jq 命令
首先确定这种情况有多常见,然后有多少用户可以安装
jq
以及有多少用户不能安装jq
。如果后一种情况很少见,请考虑使用 jq
并告知您的脚本需要 jq
才能工作。
尝试通过使用 awk、sed 操作字符串来解决此问题 和 gsup。
我不知道最后一个名为
awk
和 sed
的工具不支持使用 JSON。存在 GNU gawkextlib
的
AWK
变体,它确实支持使用 JSON 和 XML,但您需要收集依赖项并构建它,这样做的要求会增加脚本用户的负担。
使用 shell 脚本操作 JSON 对象的更简单方法,无需使用 jq
您可能会考虑使用 json
标准库中的
python
,因为 python
(及其标准库)通常安装在 Linux 计算机上,警告:您应该首先轮询用户的代表性样本以确定如果他们有 jq
或 python
或两者都可运行。
假设 JSON 文件中最顶层的结构始终是 Object 的简单示例。使用以下内容创建
upsert.py
import argparse
import json
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='UPDATE or INSERT key-value into JSON document')
parser.add_argument('key')
parser.add_argument('value')
parser.add_argument('filename')
args = parser.parse_args()
with open(args.filename, 'r') as f:
data = json.load(f)
data[args.key] = args.value
with open(args.filename, 'w') as f:
json.dump(data, f)
并让
file.json
内容为
{"A":"Able","B":"Baker","C":"Charlie"}
然后
python upsert.py 'D' 'Dog' file.json
将 file.json 内容更改为
{"A": "Able", "B": "Baker", "C": "Charlie", "D": "Dog"}
观察到,除了
D
的新条目之外,在 :
和 ,
之后添加了空格,这是默认行为。如果您想应用不同的格式,请参阅 json.dumps
文档。
(在 Python 2.7.18 和 Python 3.10.12 中测试)