如何在GNU sed中模拟BSD sed的输出换行行为?
在GNU sed中模拟BSD sed的自动追加换行行为
当然可以!问题的核心是BSD sed会强制给所有输出行追加换行符,哪怕输入行本身没有结尾的换行;而GNU sed默认会严格保留输入的换行状态。针对你处理nvidia-smi输出的场景,有几种简单可靠的方法能让GNU sed输出和BSD sed一致的结果:
方法1:在替换结果中显式添加换行符
直接修改你的sed替换逻辑,在捕获的内存数值后面加上\n,确保每个匹配项都自带换行:
loads=$(eval nvidia-smi | sed -nr 's/.*\s([0-9]+)MiB\s*\/\s*([0-9]+)MiB.*/\1 \2\n/p')
不管输入行是否有结尾换行,每个提取出的结果都会被强制加上换行符,最终echo $loads会输出两行独立的内容。
方法2:用a\命令强制追加换行
如果不想修改替换的核心逻辑,可以在每次打印匹配行后,用a\命令追加一个换行符(GNU sed中a\后无内容时会自动插入换行):
loads=$(eval nvidia-smi | sed -nr 's/.*\s([0-9]+)MiB\s*\/\s*([0-9]+)MiB.*/\1 \2/p; a\'')
这个方式相当于给每个输出的匹配行“补”上换行,逻辑更直观。
方法3:通用场景的G命令方案
如果需要处理混合有/无换行的复杂输入,可以利用G命令把保持空间的换行符(默认为空,执行G后会追加一个换行)加到模式空间末尾,再做去重处理:
loads=$(eval nvidia-smi | sed -nr 's/.*\s([0-9]+)MiB\s*\/\s*([0-9]+)MiB.*/\1 \2/; G; s/\n$//p')
这里G负责给行尾加换行,s/\n$//则避免输入行本身有换行时出现重复换行的问题,适配性更强。
为什么原始命令在GNU sed里会变成一行?
因为nvidia-smi的输出最后一行可能没有以换行符结尾(很多命令的输出都会有这种情况)。BSD sed会自动给每个输出的匹配行补全换行,而GNU sed严格遵循输入的换行状态——当输入行没有结尾换行时,p命令打印的内容也不带换行,导致两个匹配结果被直接拼接成一行。
修改命令后再测试,你会发现echo $loads的输出和BSD sed环境下完全一致:
18 11177 7 2000
内容的提问来源于stack exchange,提问作者PyariBilli
相关产品推荐
相关产品推荐

