如何在Bash中循环遍历多个正则表达式匹配结果
解决Bash中用正则循环提取多个捕获组数据的问题
我明白你的需求——要从这个包含多个JSON对象的字符串里,用正则提取每条数据的id、name和address,还要循环遍历所有匹配结果。你现在的代码只能拿到第一个匹配项,因为Bash的=~运算符默认只会执行一次匹配,咱们得调整一下逻辑来实现循环遍历。
方法一:纯Bash内置循环(无需额外工具)
先修正一下你的正则表达式(补上遗漏的闭合引号,避免匹配出错),然后通过每次匹配后截断字符串的方式,循环处理所有条目:
#!/bin/bash string=' { "id" : 45, "name" : "John Doe", "address" : "123 Fake Street" }, { "id" : 46, "name" : "Jane Doe", "address" : "234 Somewhere Road" } ' # 修正后的正则:补上了name和address值后面的闭合引号,确保匹配准确 regex='\{[^\}]*id" : ([0-9]*)[^\}]*name" : "([a-zA-Z ]*)"[^\}]*address" : "([a-zA-Z0-9 ]*)"[^\}]*\}' # 循环匹配所有条目 while [[ "$string" =~ $regex ]]; do # 从BASH_REMATCH数组中提取捕获组内容 id="${BASH_REMATCH[1]}" name="${BASH_REMATCH[2]}" address="${BASH_REMATCH[3]}" # 输出当前条目的数据(你可以换成自己的处理逻辑) echo "找到条目:ID=$id,姓名=$name,地址=$address" # 截断字符串:去掉已经处理过的匹配内容,继续处理剩余部分 string="${string#*"${BASH_REMATCH[0]}"}" done
工作原理:
- 每次循环用
=~匹配当前字符串中的第一个条目; BASH_REMATCH[0]是整个匹配的内容,BASH_REMATCH[1]/[2]/[3]对应你定义的三个捕获组;- 用
${string#*匹配内容}把字符串中匹配部分及之前的内容删除,剩下的字符串进入下一轮循环,直到没有匹配项为止。
方法二:先提取单个对象再逐个处理(更清晰)
如果字符串结构更复杂,纯Bash的截断可能容易出错,咱们可以先用grep把每个独立的{...}对象提取出来,再逐个用正则解析:
#!/bin/bash string=' { "id" : 45, "name" : "John Doe", "address" : "123 Fake Street" }, { "id" : 46, "name" : "Jane Doe", "address" : "234 Somewhere Road" } ' # 用grep提取每个独立的JSON对象(-o只输出匹配部分,-P启用Perl兼容正则) while read -r obj; do # 对单个对象应用正则提取数据 if [[ "$obj" =~ id" : ([0-9]*).*name" : "([a-zA-Z ]*)".*address" : "([a-zA-Z0-9 ]*)" ]]; then echo "找到条目:ID=${BASH_REMATCH[1]},姓名=${BASH_REMATCH[2]},地址=${BASH_REMATCH[3]}" fi done < <(grep -oP '\{[^\}]+\}' <<< "$string")
这个方法把“提取所有对象”和“解析单个对象”分开,逻辑更清晰,也更容易维护。
额外推荐:用专业工具处理JSON(更可靠)
虽然你问的是正则,但还是要提一句:如果你的字符串是标准JSON格式,用jq工具处理会比正则靠谱得多——正则处理JSON很容易因为值里的特殊字符(比如引号、转义符)出问题。用jq的示例代码:
#!/bin/bash string=' [ { "id" : 45, "name" : "John Doe", "address" : "123 Fake Street" }, { "id" : 46, "name" : "Jane Doe", "address" : "234 Somewhere Road" } ] ' # 先把字符串转成合法的JSON数组(如果原来不是的话),再用jq遍历 echo "$string" | jq -c '.[]' | while read -r item; do id=$(jq -r '.id' <<< "$item") name=$(jq -r '.name' <<< "$item") address=$(jq -r '.address' <<< "$item") echo "找到条目:ID=$id,姓名=$name,地址=$address" done
jq是专门处理JSON的工具,能完美处理各种边缘情况,建议优先考虑。
内容的提问来源于stack exchange,提问作者chrisr747
相关产品推荐
相关产品推荐

