如果GNU awk可用,@jaypal 简洁而优雅的解决方案就是要走的路。
这是一个符合 POSIX 的解决方案,它试图点 i 并交叉 t(使@jaypal 的解决方案不符合标准的原因是使用RS包含多个(文字)字符的(记录分隔符)值):
zone:根据 OP 的要求,它从输出中删除
- 它不会
\n在开头打印额外内容或省略尾随内容。
- 它使用
printf格式参数安全地使用,以避免意外控制字符。输入线的扩展。
awk'{
if ($1=="zone:") { sep=(notFirst++ ? ORS : ""); $1=""; $0=substr($0,2) }
否则 { sep=OFS; $1=$1; }
printf "%s%s", 九月, $0
}
结束{打印}
' 文件
下面是同一个程序的一个被大量评论的版本,希望能解释awk这里使用的更神秘的特性:
啊啊啊
{
if ($1=="zone:") { # 区域线
# 确定 *precede* 输出行的分隔符:
# ORS,输出*record*分隔符,默认为\n
# - 除非它是第一行。
# 净效应:区域线开始新的输出线。
sep=(notFirst++ ? ORS : "");
# 通过设置第一个字段来移除 `zone:` 字段,
# $1, 到一个空字符串。
# 注意:这会导致整条线路通过加入
# 带 OFS 的字段,输出字段分隔符,默认值
# 到一个空格。多个相邻的空格字符。被折叠成
# 一个在进程中。
$1="";
# 删除空格字符。在重建之初
# 源于将 $1 设置为空字符串的行。
$0=substr($0,2)
} else { # 非区域行
# 确定 *precede* 输出行的分隔符:
# 只是常规输出 *field* 分隔符(空格),
# 有效地导致这一行被附加到
# 前一个。
九月=OFS;
# 触发重建线以便折叠
# 多个相邻的空格字符。合而为一。
$1=$1;
}
# 输出分隔符后跟重建的行。
printf "%s%s", 九月, $0
}
# 因为上面的 `printf` 语句从不输出
# a *terminating* \n,我们在最后输出一个。
结束{打印}
' 文件