如何用grep优雅处理匹配大括号的文本内容提取?
文本格式转换方案
输入文本
VARA {APPLE} VARB { ORANGE BANANA } VARC { KIWI{0} KIWI{1} BERRY } VARD {CHERRY{0} MELON}
期望输出
VARA APPLE VARB ORANGE BANANA VARC KIWI{0} KIWI{1} BERRY VARD CHERRY{0} MELON
仅用grep的可行性
纯grep无法实现需求。grep仅擅长单模式行匹配与提取,没法处理跨多行的大括号配对逻辑,也无法识别嵌套括号(如KIWI{0})的层级关系并保留对应内容,必须借助支持状态跟踪的工具。
优雅替代方案:awk脚本
awk可以通过跟踪括号嵌套层级,将同一变量对应的多行内容合并为一行,同时保留嵌套括号的内容。脚本逻辑如下:
- 初始化括号深度
depth=0、当前变量名var、内容缓冲区content - 逐行处理文本,先去除行首尾空格
- 按字符位置优先处理
{或}:- 遇到外层
{时提取变量名,遇到嵌套{直接保留字符并增加深度 - 遇到外层
}时输出变量名+整理后的内容,遇到嵌套}直接保留字符并减少深度 - 非括号字符在括号内时,自动合并连续空格为单个空格
- 遇到外层
完整awk脚本
BEGIN { depth=0; var=""; content="" } { gsub(/^[[:space:]]+|[[:space:]]+$/, "") line = $0 while (length(line) > 0) { if (index(line, "{") < index(line, "}") || index(line, "}") == 0) { pos = index(line, "{") if (pos > 0) { if (depth == 0) { var = substr(line, 1, pos-1) gsub(/[[:space:]]+$/, "", var) line = substr(line, pos+1) } else { content = content " " substr(line, 1, pos) line = substr(line, pos+1) } depth++ } else { content = content " " line line = "" } } else { pos = index(line, "}") depth-- if (depth == 0) { content = content " " substr(line, 1, pos-1) gsub(/^[[:space:]]+|[[:space:]]+$/, "", content) print var " " content var = "" content = "" line = substr(line, pos+1) } else { content = content " " substr(line, 1, pos) line = substr(line, pos+1) } } } }
使用方法
将脚本保存为process.awk,执行命令:
awk -f process.awk 你的输入文件名.txt
备选:Shell逐字符处理脚本
如果偏好纯shell实现,也可以通过逐字符读取并跟踪括号深度来完成,逻辑和awk一致:
#!/bin/bash input="$1" depth=0 var="" content="" while IFS= read -r -n1 char; do if [[ "$char" == "{" ]]; then ((depth++)) if [[ $depth -eq 1 ]]; then var=$(echo "$var" | sed 's/[[:space:]]*$//') else content+="$char" fi elif [[ "$char" == "}" ]]; then ((depth--)) if [[ $depth -eq 0 ]]; then content=$(echo "$content" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') echo "$var $content" var="" content="" else content+="$char" fi elif [[ $depth -eq 0 ]]; then var+="$char" else if [[ "$char" =~ [[:space:]] ]]; then if [[ "${content: -1}" != " " ]]; then content+=" " fi else content+="$char" fi fi done < "$input"
使用方法
将脚本保存为process.sh,赋予执行权限后执行:
chmod +x process.sh ./process.sh 你的输入文件名.txt
内容的提问来源于stack exchange,提问作者Amir
相关产品推荐
相关产品推荐

