过去几天我一直在研究 stackexchange,我发现了我想要完成的一些事情,但我不确定如何将它们组合在一起......
我正在尝试创建一个对 API 进行curl 调用的脚本。这会返回一大堆 xml,然后我想将其解析为仅某些值。总的来说,我希望这个脚本进行调用,解析值/将它们设置为变量,然后返回(显示)它们。
我可能找到了一个工作类型的解决方案,但这实用吗?
#!/bin/bash
test=$(curl -k --silent "https://username:[email protected]?.full=true&name=devicename")
test2=$(curl -k --silent "https://username:[email protected]?.devicestatus&name=devicename")
variable1=$grep -oPm1 "(?<=<name>)[^<]+" <<< "$test:)
variable2=$grep -oPm1 "(?<=<status>)[^<]+" <<< "$test:)
echo "$variable"
echo "$variable2"
[admin]>./script SwitchName UP
这是我试图挖掘的 XML:
<?xml version="1.0" ?>
<queryResponse type="AccessPointDetails" rootUrl="https://website/webacs/api/v1/data" requestUrl="https://website/webacs/api/v1/data/AccessPointDetails?.full=true&name=devicename" responseType="listEntityInstances" count="1" first="0" last="0">
<entity url="https://website/webacs/api/v1/data/AccessPointDetails/14008947223" type="AccessPointDetails" dtoType="accessPointDetailsDTO">
<accessPointDetailsDTO id="14008947223" displayName="14008947223">
<clientCount>6</clientCount>
<clientCount_2_4GHz>0</clientCount_2_4GHz>
<clientCount_5GHz>6</clientCount_5GHz>
<ipAddress>172.16.83.5</ipAddress>
<name>devicename</name>
<unifiedApInfo>
......
</unifiedApInfo>
<upTime>609857</upTime>
</accessPointDetailsDTO>
</entity>
</queryResponse>
<?xml version="1.0" ?>
<queryResponse type="AccessPointDetails" rootUrl="https://website/webacs/api/v1/data" requestUrl="https://website/webacs/api/v1/data/AccessPointDetails?.full=true&name=devicename" responseType="listEntityInstances" count="1" first="0" last="0">
<entity url="https://website/webacs/api/v1/data/AccessPointDetails/14008947223" type="AccessPointDetails" dtoType="accessPointDetailsDTO">
<accessPointDetailsDTO id="14008947223" displayName="14008947223">
<name>devicename</name>
<status>UP</status>
<unifiedApInfo>
......
</unifiedApInfo>
</accessPointDetailsDTO>
</entity>
</queryResponse>
答案1
首先,一些评论/问题可以让您以不同的方式思考:
(换句话说,这最初是作为评论,但后来变成了实际的答案)
当您已经知道该元素时,为什么还要尝试提取该
devicename
元素 - 这是您用来获取 XML 的内容(在name=devicename
URL 中)?即使您还没有它,第二个
curl
命令(带有?.devicestatus
)也包含devicename
和status
元素,因此您只需要获取第二个命令。你的
variable1=
和variable2=
线路严重混乱。您在两行上都使用了$grep
not ,并且用一个而不是另一个双引号$(grep
终止了双引号。:
即它应该是这样的
<<< "$test"
,而不是<<< "$test:
正如其他人在评论中已经提到的,使用正则表达式来解析 XML 确实不是一个好方法。请改用 XML 处理器,例如,它
xmlstarlet
是在 shell 脚本中处理 XML 的有用工具。或者用一种语言编写脚本(例如perl
或python
具有可用的 XML 处理库的语言)。在此站点和上搜索https://stackoverflow.com/对于很多例子)。由于上面的 3. 和 4.,您的问题的答案是“不,这是不实际的,因为它根本不起作用,而且因为这里不应该使用正则表达式”。
现在提供一些可能的解决方案:
这只是修复脚本中的语法错误,以便它应该运行:
#!/bin/bash
test=$(curl -k --silent "https://username:[email protected]?.full=true&name=devicename")
test2=$(curl -k --silent "https://username:[email protected]?.devicestatus&name=devicename")
variable1=$(grep -oPm1 "(?<=<name>)[^<]+" <<< "$test1")
variable2=$(grep -oPm1 "(?<=<status>)[^<]+" <<< "$test2")
echo "$variable"
echo "$variable2"
但这远非最佳,尤其是因为正则表达式无法可靠地解析 XML。尝试这样做充其量只是一种丑陋的黑客行为,并且只有在条件(即 XML 输入)对于您尝试提取的内容绝对完美时才有效。即使服务器对 XML 输出进行很小的更改(例如消除多余的空格,包括换行符),也可能会破坏您的脚本。
如果我尝试做你正在做的事情,我大致会这样做:
#!/bin/bash
U='username'
P='password'
site='website.api.address'
element_base='queryResponse/entity'
element_AP="${element_base}/accessPointDetailsDTO"
element_status="${element_AP}/status"
devname='devicename'
url="https://${U}:${P}@${site}?.devicestatus&name=${devname}"
xml=$(curl -k --silent "$url")
status=$(printf '%s\n' "$xml" | xmlstarlet sel -t -v "$element_status")
echo "$devname: $status"
以这种方式编写脚本的有用之处之一是,通过从其他变量构建各种字符串($url
特别$element_status
是),可以轻松更改它们,而不会出现拼写错误或其他错误的风险。它们还可以来自命令行(例如U="$1" ; P="$2" ; devname="$3"
或用于getopts
处理命令行选项,如-u username -p passsword -d devicename
)或来自配置文件,或两者兼而有之。您还可以devname
在命令行上提供多个 s 并在循环中获取它们。
这是该脚本的另一个版本,结合了其中一些想法:
#!/bin/bash
# get username and password, and remove them from the args
U="$1" ; shift
P="$1" ; shift #edited. was $2
site='website.api.address'
element_base='queryResponse/entity'
element_AP="${element_base}/accessPointDetailsDTO"
element_status="${element_AP}/status"
url="https://${U}:${P}@${site}?.devicestatus"
for devname in "$@" ; do
xml=$(curl -k --silent "${url}&name=${devname}")
status=$(printf '%s\n' "$xml" | xmlstarlet sel -t -v "$element_status")
echo "$devname: $status"
done