如何在Bash中用Awk/Grep匹配两行字符串并提取指定内容
问题与解决方案
场景说明
现有data.txt内容如下:
"line1":"text1", "line2":"text2", "line3":"text3", "line4":"text4", "line5":"text5", "line6":"text6", "line7":"text7", "line8":"text8", "line9":"text9", "line10":"text10"
需要完成两个目标:
- 匹配文件中包含
"line7":"text7",和"line8":"text8",的连续行块 - 提取该行块前3行里
line4和line5对应的text值,存入Bash变量content_of_line4和content_of_line5
之前尝试的grep命令失效,原因是默认grep按行处理,\n无法匹配文件里的实际换行,且转义写法冗余。
解决方法一:用grep -z实现多行匹配
grep -z会把整个文件当成单一数据流,支持跨多行匹配,配合Perl风格正则可以精准提取内容:
# 匹配目标行块及前3行,转成正常换行格式 result=$(grep -z -oP '(.*\n){3}"line7":"text7",\n"line8":"text8",' data.txt | tr '\0' '\n') # 提取line4的text值(只取引号里的内容) content_of_line4=$(echo "$result" | grep -oP '"line4":"\K[^"]+') # 提取line5的text值 content_of_line5=$(echo "$result" | grep -oP '"line5":"\K[^"]+') # 验证结果 echo "line4内容: $content_of_line4" echo "line5内容: $content_of_line5"
-z:让grep忽略换行,把文件视为连续文本,这样正则里的\n能匹配实际换行-oP:-o只输出匹配到的内容,-P启用Perl风格正则,\K用来跳过前面的"line4":",直接提取后面的text内容tr '\0' '\n':把grep输出的NUL分隔符转成换行,方便后续处理
解决方法二:用awk做行缓存处理
awk天生适合处理行关联场景,逻辑更直观,适合复杂的行匹配需求:
# 用awk缓存行内容,匹配到目标行块时输出line4和line5 awk ' # 检测到line7且下一行是line8时,输出缓存的line4和line5 $0 == "\"line7\":\"text7\"," && getline next_line && next_line == "\"line8\":\"text8\"," { print line4; print line5 } # 持续缓存最近3行,同时单独记录line4和line5的行内容 { line3=line2; line2=line1; line1=$0 if ($0 ~ /"line4":"[^"]+"/) line4=$0 if ($0 ~ /"line5":"[^"]+"/) line5=$0 } ' data.txt | while read -r l4 && read -r l5; do # 提取text值赋值给变量 content_of_line4=$(echo "$l4" | grep -oP '"line4":"\K[^"]+') content_of_line5=$(echo "$l5" | grep -oP '"line5":"\K[^"]+') done # 验证结果 echo "line4内容: $content_of_line4" echo "line5内容: $content_of_line5"
- 用
line1/line2/line3缓存最近3行的内容,同时专门缓存line4和line5的完整行 - 当检测到
line7和下一行是line8时,输出之前缓存的line4和line5 - 通过
while循环把awk的输出赋值给目标变量
内容的提问来源于stack exchange,提问作者Saeed
相关产品推荐
相关产品推荐

