如何在Bash中包含以空格开头的换行符?
嘿,针对你遇到的Bash环境中处理含空格开头换行符的文本问题,我给你整理了几个实用的解决方案,都是实际场景里常用的技巧:
先明确咱们要处理的原始文本样式:
标题与作者 电子文本编号
《植物生命面面观;特别关注英国植物区系》,电子文本编号56900,作者:罗伯特·劳埃德·普雷格
《莫恩斯托教区牧师》,作者:萨拜因·巴林-古尔德,电子文本编号56899
[副标题:罗伯特·斯蒂芬·霍克生平,文学硕士]
《圣经研究IV》,作者:查尔斯·T·拉塞尔,电子文本编号56898
[副标题:哈米吉多顿之战]
[语言:芬兰语]
《圣经研究III》,作者:查尔斯·T·拉塞尔,电子文本编号56897
[副标题:愿你的国降临]
[语言:芬兰语]
这类文本的问题在于,副标题、语言这类附属信息以空格开头的换行单独成行,我们需要把它们合并到对应主条目,或者提取结构化信息。
方法1:快速合并空格开头的行到上一行
用sed就能轻松搞定,这是最常用的单行命令:
sed ':a; N; s/\n / /; ta' input.txt
命令解释:
:a定义一个循环标签aN读取下一行内容到当前处理的缓冲区s/\n / /把“换行+空格”替换成单个空格,实现行合并ta如果替换成功,跳回标签a继续处理(支持连续多行空格开头的情况)
运行后输出会变成每条完整条目占一行:
《植物生命面面观;特别关注英国植物区系》,电子文本编号56900,作者:罗伯特·劳埃德·普雷格
《莫恩斯托教区牧师》,作者:萨拜因·巴林-古尔德,电子文本编号56899 [副标题:罗伯特·斯蒂芬·霍克生平,文学硕士]
《圣经研究IV》,作者:查尔斯·T·拉塞尔,电子文本编号56898 [副标题:哈米吉多顿之战] [语言:芬兰语]
《圣经研究III》,作者:查尔斯·T·拉塞尔,电子文本编号56897 [副标题:愿你的国降临] [语言:芬兰语]
方法2:提取结构化字段(标题/作者/编号等)
如果需要把文本拆解成结构化的信息(比如单独提取标题、作者、编号),用awk写个小脚本最合适:
awk '{ # 判断当前行是否以空格开头,是就拼接到上一行 if ($0 ~ /^ /) { prev = prev " " $0 } else { # 非空格开头行,先处理之前拼接好的内容 if (prev != "") print_process(prev) prev = $0 } } # 处理最后一行内容 END { if (prev != "") print_process(prev) } # 定义字段提取函数 function print_process(line) { # 匹配标题(《》包裹的内容) match(line, /《[^》]+》/, title) # 匹配作者(作者:开头到逗号前) match(line, /作者:[^,]+/, author) # 匹配电子文本编号 match(line, /电子文本编号[0-9]+/, id) # 匹配副标题(如果存在) match(line, /副标题:[^]]+/, subtitle) # 匹配语言(如果存在) match(line, /语言:[^]]+/, lang) # 格式化输出,处理字段为空的情况 printf "标题: %s\n作者: %s\n编号: %s\n", title[0] ? substr(title[0],2,length(title[0])-2) : "无", author[0] ? substr(author[0],4) : "无", id[0] ? substr(id[0],6) : "无" if (subtitle[0]) printf "副标题: %s\n", substr(subtitle[0],5) if (lang[0]) printf "语言: %s\n", substr(lang[0],4) printf "---\n" }' input.txt
脚本逻辑:
- 先把所有空格开头的行合并到对应主条目行
- 用正则匹配提取各个字段
- 格式化输出,缺失的字段会显示“无”
运行后会得到清晰的结构化结果:
标题: 植物生命面面观;特别关注英国植物区系
作者: 罗伯特·劳埃德·普雷格
编号: 56900标题: 莫恩斯托教区牧师
作者: 萨拜因·巴林-古尔德
编号: 56899
副标题: 罗伯特·斯蒂芬·霍克生平,文学硕士标题: 圣经研究IV
作者: 查尔斯·T·拉塞尔
编号: 56898
副标题: 哈米吉多顿之战
语言: 芬兰语标题: 圣经研究III
作者: 查尔斯·T·拉塞尔
编号: 56897
副标题: 愿你的国降临
语言: 芬兰语
方法3:简洁版合并(适合简单场景)
如果没有连续多层空格开头的行,用paste配合sed的组合更简洁:
sed 's/^ /\t/' input.txt | paste -s -d '\n ' | sed 's/\t/ /'
步骤解释:
- 把所有空格开头行的首空格换成制表符
- 用
paste -s合并所有行,遇到制表符用空格替换,普通换行保留 - 最后把制表符换回空格,完成合并
内容的提问来源于stack exchange,提问作者Azazel

