jq

1.  jq简介与安装    

    jq是一款命令行下处理JSON数据的工具。

    其可以接受标准输入,命令管道或者文件中的JSON数据,经过一系列的过滤器(filters)和表达式的转后形成我们需要的数据结构并将结果输出到标准输出中。

    jq的这种特性使我们可以很容易地在Shell脚本中调用它。

1) jq编译安装
jq 的源代码可以从其代码仓库中获得。编译 jq 的指令如下:
[root@ss-server ~]# git clone https://github.com/stedolan/jq.git
[root@ss-server ~]# cd jq
[root@ss-server ~]# autoreconf -i
[root@ss-server ~]# ./configure --disable-maintainer-mode
[root@ss-server ~]# make
[root@ss-server ~]# make install
 
2)jq直接安装(centos7可以直接yum安装jq)
[root@ss-server ~]# yum install -y jq
[root@ss-server ~]# jq --version
jq-1.5

2.  基本用法

一.  格式化

1.  将一行数据使用json格式输出

[root@k8s-master ~]# echo -n '{"id":1, "name":"zhangsan", "score":[75, 85, 90]}'|jq .
{
  "id": 1,
  "name": "zhangsan",
  "score": [
    75,
    85,
    90
  ]
}

(2).  将json格式输出到一行

[root@k8s-master ~]# jq -c . <<eof
> {
>   "id": 1,
>   "name": "zhangsan",
>   "score": [
>     75,
>     85,
>     90
>   ]
> }
> eof
{"id":1,"name":"zhangsan","score":[75,85,90]} 

二.  属性提取

1.  取id的值

[root@k8s-master ~]# echo  '{"id":1, "name":"zhangsan", "score":[75, 85, 90]}' | jq '.id'
1

2.  取name的值

[root@k8s-master ~]# echo  '{"id":1, "name":"zhangsan", "score":[75, 85, 90]}' | jq '.name'
"zhangsan"

3.  取name的值,去掉双引号

[root@k8s-master ~]# echo  '{"id":1, "name":"zhangsan", "score":[75, 85, 90]}' | jq -r '.name'
zhangsan

 4.  取多层值

[root@k8s-master ~]# echo -n '{"id":1, "name":"zhangsan", "attr":{"height":1.78,"weight":"60kg"}}'|jq '.attr.height'
1.78

5.  取数组值

$ echo -n '{"id":1, "name":"zhangsan", "score":[75, 85, 90]}'|jq -r '.score[0]'
75
 
$ echo -n '[75, 85, 90]'|jq -r '.[0]'
75
 
# 数组截取
$ echo -n '[75, 85, 90]'|jq -r '.[1:3]'
[
  85,
  90
]
 
# []展开数组
$ echo -n '[75, 85, 90]'|jq '.[]'
75
85
90

 6.  展开所有结构

[root@k8s-master ~]# echo  '{"id":1, "name":"zhangsan", "score":[75, 85, 90]}' | jq -c '..'
{"id":1,"name":"zhangsan","score":[75,85,90]}
1
"zhangsan"
[75,85,90]
75
85
90

7.  其他情况

# 从非对象类型中提取字段,会报错
$ echo -n '{"id":1, "name":"zhangsan", "attr":{"height":1.78,"weight":"60kg"}}'|jq '.name.alias'
jq: error (at <stdin>:0): Cannot index string with string "alias"
 
# 使用?号可以避免这种报错
$ echo -n '{"id":1, "name":"zhangsan", "attr":{"height":1.78,"weight":"60kg"}}'|jq '.name.alias?'
 
# //符号用于,当前面的表达式取不到值时,执行后面的表达式
$ echo -n '{"id":1, "name":"zhangsan", "attr":{"height":1.78,"weight":"60kg"}}'|jq '.alias//.name'
"zhangsan"

三.  管道,逗号与括号

1.  管道可以将值从前一个命令传送到后一个命令

[root@k8s-master ~]# echo -n '{"id":1, "name":"zhangsan", "attr":{"height":1.78,"weight":"60kg"}}'|jq '.attr|.height'
1.78

2.  可以做一些简单的运算

$ echo -n '{"id":1, "name":"zhangsan", "attr":{"height":1.78,"weight":"60kg"}}'|jq '.attr|.height*100|tostring + "cm"'
"178cm"

3. 使用逗号可以输出多个结果

[root@k8s-master ~]# echo -n '{"id":1, "name":"zhangsan", "attr":{"height":1.78,"weight":"60kg"}}'|jq -r '.attr.height,.attr.weight'
1.78
60kg

四.  将读取的元素,都当作字符串,使用-R参数

[root@k8s-master ~]# seq 4 | jq -R '.'
"1"
"2"
"3"
"4"

五.  将json元素,变成json数组元素

[root@k8s-master ~]# echo -n '{"id":1, "name":"zhangsan"}' | jq -s '.'
[
  {
    "id": 1,
    "name": "zhangsan"
  }
]

六.  数据构造

$ cat data.txt
id  name      age  score
1   zhangsan  17   75
2   lisi      16   80
3   wangwu    18   85
4   zhaoliu   18   90
 
# 每行分割成数组,[]构造新的数组输出
$ tail -n+2 data.txt|jq -R '[splits("\\s+")]' -c
["1","zhangsan","17","75"]
["2","lisi","16","80"]
["3","wangwu","18","85"]
["4","zhaoliu","18","90"]
 
$ jq -n '{id:1, name:"zhangsan"}' -c
{"id":1,"name":"zhangsan"}
 
# 每行转换为对象,{}构造新的对象格式输出
$ tail -n+2 data.txt|jq -R '[splits("\\s+")] | {id:.[0]|tonumber, name:.[1], age:.[2], score:.[3]}' -c
{"id":1,"name":"zhangsan","age":"17","score":"75"}
{"id":2,"name":"lisi","age":"16","score":"80"}
{"id":3,"name":"wangwu","age":"18","score":"85"}
{"id":4,"name":"zhaoliu","age":"18","score":"90"}
 
# \()字符串占位变量替换
$ cat data.json
{"id":1,"name":"zhangsan","age":"17","score":"75"}
{"id":2,"name":"lisi","age":"16","score":"80"}
{"id":3,"name":"wangwu","age":"18","score":"85"}
{"id":4,"name":"zhaoliu","age":"18","score":"90"}
 
$ cat data.json |jq '"id:\(.id),name:\(.name),age:\(.age),score:\(.score)"' -r
id:1,name:zhangsan,age:17,score:75
id:2,name:lisi,age:16,score:80
id:3,name:wangwu,age:18,score:85
id:4,name:zhaoliu,age:18,score:90 

七.  基础函数

# has函数,检测对象是否包含key
$ echo -n '{"id":1,"name":"zhangsan","age":"17","score":"75"}'|jq 'has("id")'
true
 
# del函数,删除某个属性
$ echo -n '{"id":1,"name":"zhangsan","age":"17","score":"75"}'|jq 'del(.id)' -c
{"name":"zhangsan","age":"17","score":"75"}
 
# map函数,对数组中每个元素执行表达式计算,计算结果组织成新数组
$ seq 4|jq -s 'map(. * 2)' -c
[2,4,6,8]
 
# 上面map函数写法,其实等价于这个写法
$ seq 4|jq -s '[.[]|.*2]' -c
[2,4,6,8]
 
# keys函数,列出对象属性
$ echo -n '{"id":1,"name":"zhangsan","age":"17","score":"75"}'|jq 'keys' -c
["age","id","name","score"]
 
# to_entries函数,列出对象键值对
$ echo -n '{"id":1,"name":"zhangsan","age":"17","score":"75"}'|jq 'to_entries' -c
[{"key":"id","value":1},{"key":"name","value":"zhangsan"},{"key":"age","value":"17"},{"key":"score","value":"75"}]
 
# length函数,计算数组或字符串长度
$ jq -n '[1,2,3,4]|length'
4
 
# add函数,计算数组中数值之和
$ seq 4|jq -s 'add'
10
 
# tostring与tonumber,类型转换
$ seq 4|jq 'tostring|tonumber'
1
2
3
4
 
# type函数,获取元素类型
$ jq 'type' <<eof
1
"zhangsan"
true
null
{"id":1}
[75, 80, 85]
eof
 
"number"
"string"
"boolean"
"null"
"object"
"array"

八.  过滤,排序,分组函数

$ cat data.json
{"id":1,"name":"zhangsan","sex": 0, "age":"17","score":"75"}
{"id":2,"name":"lisi","sex": 1, "age":"16","score":"80"}
{"id":3,"name":"wangwu","sex": 0, "age":"18","score":"85"}
{"id":4,"name":"zhaoliu","sex": 0, "age":"18","score":"90"}
 
# select函数用于过滤,类似SQL中的where
$ cat data.json |jq 'select( (.id>1) and (.age|IN("16","17","18")) and (.name != "lisi") or (has("attr")|not) and (.score|tonumber >= 90) )' -c
{"id":3,"name":"wangwu","sex":0,"age":"18","score":"85"}
{"id":4,"name":"zhaoliu","sex":0,"age":"18","score":"90"}
 
# 有一些简化的过滤函数,如arrays, objects, iterables, booleans, numbers, normals, finites, strings, nulls, values, scalars
# 它们根据类型过滤,如objects过滤出对象,values过滤出非null值等
$ jq -c 'objects' <<eof
1
"zhangsan"
true
null
{"id":1}
[75, 80, 85]
eof
 
{"id":1}
 
$ jq -c 'values' <<eof
1
"zhangsan"
true
null
{"id":1}
[75, 80, 85]
eof
 
1
"zhangsan"
true
{"id":1}
[75,80,85]
 
# 选择出id与name字段,类似SQL中的select id,name
$ cat data.json|jq -s 'map({id,name})[]' -c
{"id":1,"name":"zhangsan"}
{"id":2,"name":"lisi"}
{"id":3,"name":"wangwu"}
{"id":4,"name":"zhaoliu"}
 
# 提取前2行,类似SQL中的limit 2
$ cat data.json|jq -s 'limit(2; map({id,name})[])' -c
{"id":1,"name":"zhangsan"}
{"id":2,"name":"lisi"}
 
# 按照age、id排序,类似SQL中的order by age,id
$ cat data.json|jq -s 'sort_by((.age|tonumber), .id)[]' -c
{"id":2,"name":"lisi","sex":1,"age":"16","score":"80"}
{"id":1,"name":"zhangsan","sex":0,"age":"17","score":"75"}
{"id":3,"name":"wangwu","sex":0,"age":"18","score":"85"}
{"id":4,"name":"zhaoliu","sex":0,"age":"18","score":"90"}
 
 
# 根据sex与age分组,并每组聚合计算count(*)、avg(score)、max(id)
$ cat data.json |jq -s 'group_by(.sex, .age)[]' -c
[{"id":1,"name":"zhangsan","sex":0,"age":"17","score":"75"}]
[{"id":3,"name":"wangwu","sex":0,"age":"18","score":"85"},{"id":4,"name":"zhaoliu","sex":0,"age":"18","score":"90"}]
[{"id":2,"name":"lisi","sex":1,"age":"16","score":"80"}]
 
$ cat data.json |jq -s 'group_by(.sex, .age)[]|{sex:.[0].sex, age:.[0].age, count:length, avg_score:map(.score|tonumber)|(add/length), scores:map(.score)|join(","), max_id:map(.id)|max }' -c                
{"sex":0,"age":"17","count":1,"avg_score":75,"scores":"75","max_id":1}
{"sex":0,"age":"18","count":2,"avg_score":87.5,"scores":"85,90","max_id":4}
{"sex":1,"age":"16","count":1,"avg_score":80,"scores":"80","max_id":2}

九.  字符串操作函数

# contains函数,判断是否包含,实际也可用于判断数组是否包含某个元素
$ echo hello | jq -R 'contains("he")'
true
 
# 判断是否以he开头
$ echo hello | jq -R 'startswith("he")'
true
 
# 判断是否以llo结尾
$ echo hello | jq -R 'endswith("llo")'
true
 
# 去掉起始空格
$ echo ' hello '|jq -R 'ltrimstr(" ")|rtrimstr(" ")'
"hello"
 
# 大小写转换
$ echo hello|jq -R 'ascii_upcase'
"HELLO"
 
$ echo HELLO|jq -R 'ascii_downcase'
"hello"
 
# 字符串数组,通过逗号拼接成一个字符串
$ seq 4|jq -s 'map(tostring)|join(",")'
"1,2,3,4"
 
# json字符串转换为json对象
$ echo -n '{"id":1,"name":"zhangsan","age":"17","attr":"{\"weight\":56,\"height\":178}"}'|jq '.attr = (.attr|fromjson)' -c
{"id":1,"name":"zhangsan","age":"17","attr":{"weight":56,"height":178}}
 
# json对象转换为json字符串
$ echo -n '{"id":1,"name":"zhangsan","age":"17","attr":{"weight":56,"height":178}}'|jq '.attr = (.attr|tojson)'
{
  "id": 1,
  "name": "zhangsan",
  "age": "17",
  "attr": "{\"weight\":56,\"height\":178}"
}
 
$ cat data.txt
id:1,name:zhangsan,age:17,score:75
id:2,name:lisi,age:16,score:80
id:3,name:wangwu,age:18,score:85
id:4,name:zhaoliu,age:18,score:90
 
# 正则表达式过滤,jq使用的是PCRE
$ cat data.txt|jq -R 'select(test("id:\\d+,name:\\w+,age:\\d+,score:8\\d+"))' -r
id:2,name:lisi,age:16,score:80
id:3,name:wangwu,age:18,score:85
 
# 正则拆分字符串
$ cat data.txt|jq -R '[splits(",")]' -cr
["id:1","name:zhangsan","age:17","score:75"]
["id:2","name:lisi","age:16","score:80"]
["id:3","name:wangwu","age:18","score:85"]
["id:4","name:zhaoliu","age:18","score:90"]
 
# 正则替换字符串
$ cat data.txt |jq -R 'gsub("name"; "nick")' -r
id:1,nick:zhangsan,age:17,score:75
id:2,nick:lisi,age:16,score:80
id:3,nick:wangwu,age:18,score:85
id:4,nick:zhaoliu,age:18,score:90
 
# 正则表达式捕获数据
$ cat data.txt|jq -R 'match("id:(?<id>\\d+),name:(?<name>\\w+),age:\\d+,score:8\\d+")' -cr
{"offset":0,"length":30,"string":"id:2,name:lisi,age:16,score:80","captures":[{"offset":3,"length":1,"string":"2","name":"id"},{"offset":10,"length":4,"string":"lisi","name":"name"}]}
{"offset":0,"length":32,"string":"id:3,name:wangwu,age:18,score:85","captures":[{"offset":3,"length":1,"string":"3","name":"id"},{"offset":10,"length":6,"string":"wangwu","name":"name"}]}
 
# capture命名捕获,生成key是捕获组名称,value是捕获值的对象
$ cat data.txt|jq -R 'capture("id:(?<id>\\d+),name:(?<name>\\w+),age:\\d+,score:8\\d+")' -rc
{"id":"2","name":"lisi"}
{"id":"3","name":"wangwu"}
 
# 正则扫描输入字符串
$ cat data.txt|jq -R '[scan("\\w+:\\w+")]' -rc
["id:1","name:zhangsan","age:17","score:75"]
["id:2","name:lisi","age:16","score:80"]
["id:3","name:wangwu","age:18","score:85"]
["id:4","name:zhaoliu","age:18","score:90"]

十.  日期函数

# 当前时间缀
$ jq -n 'now'
1653820640.939947
 
# 将时间缀转换为0时区的分解时间(broken down time),形式为 年 月 日 时 分 秒 dayOfWeek dayOfYear
$ jq -n 'now|gmtime' -c
[2022,4,29,10,45,5.466768980026245,0,148]
 
# 将时间缀转换为本地时区的分解时间(broken down time)
$ jq -n 'now|localtime' -c
[2022,4,29,18,46,5.386353015899658,0,148]
 
# 分解时间转换为时间串
$ jq -n 'now|localtime|strftime("%Y-%m-%dT%H:%M:%S")' -c
"2022-05-29T18:50:33"
 
# 与上面等效
$ jq -n 'now|strflocaltime("%Y-%m-%dT%H:%M:%SZ")'
"2022-05-29T19:00:40Z"
 
# 时间串解析为分解时间
$ date +%FT%T|jq -R 'strptime("%Y-%m-%dT%H:%M:%S")' -c
[2022,4,29,18,51,27,0,148]
 
# 分解时间转换为时间缀
$ date +%FT%T|jq -R 'strptime("%Y-%m-%dT%H:%M:%S")|mktime'
1653850310 

十一.  高级用法

$ cat data.json
{"id":1,"name":"zhangsan","sex": 0, "age":"17","score":"75"}
{"id":2,"name":"lisi","sex": 1, "age":"16","score":"80"}
{"id":3,"name":"wangwu","sex": 0, "age":"18","score":"85"}
{"id":4,"name":"zhaoliu","sex": 0, "age":"18","score":"90"}
 
# 单变量定义
$ cat data.json| jq '.id as $id|$id'
1
2
3
4
 
# 对象展开式变量定义
$ cat data.json |jq '. as {id:$id,name:$name}|"id:\($id),name:\($name)"'
"id:1,name:zhangsan"
"id:2,name:lisi"
"id:3,name:wangwu"
"id:4,name:zhaoliu"
 
$ cat data.json
["1","zhangsan","17","75"]
["2","lisi","16","80"]
["3","wangwu","18","85"]
["4","zhaoliu","18","90"]
 
# 数组展开式变量定义
$ cat data.json|jq '. as [$id,$name]|"id:\($id),name:\($name)"'
"id:1,name:zhangsan"
"id:2,name:lisi"
"id:3,name:wangwu"
"id:4,name:zhaoliu"
 
# 分支结构
$ cat data.json|jq '. as [$id,$name]|if ($id>"1") then "id:\($id),name:\($name)" else empty end'
"id:2,name:lisi"
"id:3,name:wangwu"
"id:4,name:zhaoliu"
 
# 循环结构,第一个表达式条件满足时,执行只每二个表达式
# 循环结构除了while,还有until、recurse等
$ echo 1|jq 'while(.<100; .*2)'
1
2
4
8
16
32
64
 
# 自定义计算3次方的函数
$ echo 2|jq 'def cube: .*.*. ; cube'
8

CDN 筛选

#!/bin/bash
##版本:V2.1.2
#新功能,支持ip地址全自动下载,更新优选完毕后推送至TG,再也不怕脚本没有成功运行了。
#使用脚本需要安装jq和timeout,新增openwrt专用cf_RE.sh文件,运行cf_RE.sh即可在openwrt安装jq和timeout两个扩展。
#其他linux请自行安装jq和timeout。
#主程序为ip_down.sh。

###################################################################################################
export LANG=zh_CN.UTF-8
###################################################################################################

##cloudflare配置
#cloudflare账号邮箱
x_email=*********************
#填写需要DDNS的完整域名
#支持多域名:域名需要填写在括号中,每个域名之间用“空格”相隔。
#例如:(cdn.test.com) 或者 (cdn1.test.com cdn2.test.com cdn3.test.com)
CDNhostname=****************
#区域ID
zone_id=********************************
#Global API Key(获取你的API令牌,你的API密钥就是你的登陆密码)
api_key=****************************
$CLIEN=v2raya.service
###################################################################################################
##CloudflareST配置
#测速地址
CFST_URL=https://download.parallels.com/desktop/v15/15.1.5-47309/ParallelsDesktop-15.1.5-47309.dmg
#测速线程数量;越多测速越快,性能弱的设备 (如路由器) 请勿太高;(默认 200 最多 1000 )
CFST_N=200
# 指定测速端口;延迟测速/下载测速时使用的端口;(默认 443 端口)
CFST_TP=8443
#下载测速数量;延迟测速并排序后,从最低延迟起下载测速的数量;(默认 10 个)
CFST_DN=10
#平均延迟上限;只输出低于指定平均延迟的 IP,可与其他上限/下限搭配;(默认9999 ms 这里推荐配置250 ms)
CFST_TL=250
#平均延迟下限;只输出高于指定平均延迟的 IP,可与其他上限/下限搭配、过滤假墙 IP;(默认 0 ms 这里推荐配置40)
CFST_TLL=40
#下载速度下限;只输出高于指定下载速度的 IP,凑够指定数量 [-dn] 才会停止测速;(默认 0.00 MB/s 这里推荐5.00MB/s)
CFST_SL=3
#更新几个 默认10个
CFST_P=10
#####################################################################################################
# 定义下载链接和保存路径
download_url=”https://zip.baipiao.eu.org/”
save_path=”/root/txt.zip”
extracted_folder=”/root/txt” # 解压后的文件夹路径
###################################################################################################

# 定义最大尝试次数
max_attempts=10
current_attempt=1
###################################################################################################
# 关闭开启科学上网
systemctl stop $CLIEN;
#sleep 20s
# 循环尝试下载
while [ $current_attempt -le $max_attempts ]
do
# 下载文件
wget “${download_url}” -O $save_path

# 检查是否下载成功
if [ $? -eq 0 ]; then
break
else
echo “Download attempt $current_attempt failed.”
current_attempt=$((current_attempt+1))
fi
done
###################################################################################################

# 检查是否下载成功
if [ $current_attempt -gt $max_attempts ]; then
echo “Failed to download the file after $max_attempts attempts.”
else
# 删除原来的txt文件夹内容
rm -rf $extracted_folder/*

# 解压文件
unzip $save_path -d $extracted_folder

# 删除压缩包
rm $save_path

echo “File downloaded and unzipped successfully.”
###################################################################################################
# 合并文件为ip.txt
# 合并所有含有-1-443.txt的文本文件到一个新文件中
merged_file=”/root/CloudflareST/merged_ip.txt”
cat $extracted_folder/*-1-$CFST_TP.txt > $merged_file
###################################################################################################
# 移动到ip.txt到程序总目录

# 将合并后的文件移动到/root/CloudflareST/ip.txt并覆盖原文件
mv -f “$merged_file” “/root/cdn/ip.txt”
echo “Merged text files containing ‘-1-$CFST_TP.txt’ moved and renamed as ‘ip.txt’ in /root/cdn.”
fi
###################################################################################################
ipv4Regex=”((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])”;
#默认关闭小云朵
proxy=”false”;
#验证cf账号信息是否正确
res=$(curl -s -X GET “https://api.cloudflare.com/client/v4/zones/${zone_id}” -H “X-Auth-Email:$x_email” -H “X-Auth-Key:$api_key” -H “Content-Type:application/json”);
resSuccess=$(echo “$res” | jq -r “.success”);
if [[ $resSuccess != “true” ]]; then
pushmessage=”登陆错误,检查cloudflare账号信息填写是否正确!”
# source cf_push;
exit 1;
fi
echo “Cloudflare账号验证成功”;
#停止科学上网服务

systemctl stop $CLIEN;
echo “已停止$CLIEN”;


#判断是否配置测速地址
if [[ “$CFST_URL” == http* ]] ; then
CFST_URL_R=”-url $CFST_URL”;
else
CFST_URL_R=””;
fi

if [ “$IP_ADDR” = “ipv6” ] ; then
#开始优选IPv6
./CloudflareST $CFST_URL_R -tp $CFST_TP -n $CFST_N -dn $CFST_DN -tl $CFST_TL -tll $CFST_TLL -sl $CFST_SL -p $CFST_P -f ipv6.txt
else
#开始优选IPv4
./CloudflareST $CFST_URL_R -tp $CFST_TP -n $CFST_N -dn $CFST_DN -tl $CFST_TL -tll $CFST_TLL -sl $CFST_SL -p $CFST_P
fi
echo “测速完毕”;
#systemctl start $CLIEN;
#echo “已重启$CLIEN”;
echo “为保证cloudflareAPI连接正常 将在30秒后开始更新域名解析”;
sleep 3s;
#开始循环
echo “正在更新域名,请稍后…”;
x=0;
#while [[ ${x} -lt $num ]]; do
# CDNhostname=${hostname[$x]};
#获取优选后的ip地址

# ipAddr=$(sed -n “$((x + 2)),1p” result.csv | awk -F, ‘{print $1}’);
# echo “开始更新第$((x + 1))个—$ipAddr”;

while (($x<3))
do
ipAddr[$x]=$(sed -n “$((x + 2)),1p” result.csv | awk -F, ‘{print $1}’);
echo “更新的IP${ipAddr[$x]}”;
let “x++”;
done
#开始DDNS
#if [[ $ipAddr =~ $ipv4Regex ]]; then
recordType=”A”;
# else
recordType=”AAAA”;
# fi
# listDnsApi=”https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records?type=${recordType}&name=${CDNhostname}”;
# createDnsApi=”https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records”;

# res=$(curl -s -X GET “$listDnsApi” -H “X-Auth-Email:$x_email” -H “X-Auth-Key:$api_key” -H “Content-Type:application/json”);



# 获取现有记录ID(如果存在)
res=$(curl -s -X GET “https://api.cloudflare.com/client/v4/zones/${zone_id}//dns_records?type=A&name=$CDNhostname” \
-H “Authorization: Bearer $api_key” \
-H “X-Auth-Email:$x_email” \
-H “X-Auth-Key:$api_key”\
-H “Content-Type:application/json”)
#EXISTING_RECORD_ID=$(echo “$res” | jq -r “.result[$id].id”)
# echo ${EXISTING_RECORD_ID};

i=0;
for IP in “${ipAddr[@]}”
do
recordId=$(echo “$res” | jq -r “.result[$i].id”);
recordIp=$(echo “$res” | jq -r “.result[$i].content”);
echo “$recordId”
if [[ $recordIp = “$IP” ]]; then
echo “更新失败,获取最快的IP与云端相同”;
resSuccess=false;
elif [[ $recordId = “null” ]]; then
sleep 3s;
res_Success =$(curl -s -X POST “https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records” \
-H “Authorization: Bearer $api_key” \
-H “X-Auth-Email:$x_email” \
-H “X-Auth-Key:$api_key”\
-H “Content-Type: application/json” \
–data ‘{
“type”: “A”,
“name”: “‘$CDNhostname'”,
“content”: “‘$IP'”,
“ttl”: 60,
“proxied”: false
}’);
resSuccess=$(echo “res_Success” | jq -r “.success”);
# echo “Added A record for $CDNhostname with IP: $IP”;
else
sleep 3s;
res_Success=$(curl -s -X PUT “https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records/$recordId” \
-H “Authorization: Bearer $api_key” \
-H “X-Auth-Email:$x_email” \
-H “X-Auth-Key:$api_key”\
-H “Content-Type: application/json” \
–data ‘{
“type”: “A”,
“name”: “‘$CDNhostname'”,
“content”: “‘$IP'”,
“ttl”: 60,
“proxied”: false
}’);
#echo “Updated A record for $CDNhostname with IP: $IP”
resSuccess=$(echo “$res_Success” | jq -r “.success”);
# echo “Updated A record for $CDNhostname with IP: $IP”;
fi

if [[ $resSuccess = “true” ]]; then
echo “$CDNhostname更新成功$IP”;
else
echo “$CDNhostname更新失败$IP”;
fi
let “i++”;

#会生成一个名为informlog的临时文件作为推送的内容。
done > informlog
pushmessage=$(cat informlog);
systemctl start $CLIEN;
echo “已停止$CLIEN”;
#source cf_push;
exit 0;