Sed 如何根据相邻行的第一个字段是否为空来连接它们?
我是否可以根据前几个字符是否为空,在前一行后面追加一行 例如,我有以下数据:Sed 如何根据相邻行的第一个字段是否为空来连接它们?,sed,awk,text-parsing,reformat,Sed,Awk,Text Parsing,Reformat,我是否可以根据前几个字符是否为空,在前一行后面追加一行 例如,我有以下数据: zone: z_ABCSVR01_STORAGE1 ABCSVR; STORAGE1_P1; STORAGE_P2 zone: z_SUNSVR1_NBUSANCP SUNSVR1; NBUSANCP; zone: z_WINSVR01_STORAGE2 WINSVR01; STORAGE1_P2;
zone: z_ABCSVR01_STORAGE1
ABCSVR; STORAGE1_P1;
STORAGE_P2
zone: z_SUNSVR1_NBUSANCP
SUNSVR1; NBUSANCP;
zone: z_WINSVR01_STORAGE2
WINSVR01; STORAGE1_P2;
STORAGE_P3
我需要下面的输出:
z_ABCSVR01_STORAGE1 ABCSVR; STORAGE1_P1; STORAGE_P2
z_SUNSVR1_NBUSANCP SUNSVR1; NBUSANCP;
z_WINSVR01_STORAGE2 WINSVR01; STORAGE1_P2; STORAGE_P3
使用awk
awk '{printf (/^zone/)?RS $0:FS $0}' file
zone: z_ABCSVR01_STORAGE1 ABCSVR; STORAGE1_P1; STORAGE_P2
zone: z_SUNSVR1_NBUSANCP SUNSVR1; NBUSANCP;
zone: z_WINSVR01_STORAGE2 WINSVR01; STORAGE1_P2; STORAGE_P3
或
如果需要删除无用的空白:
awk '{printf (/^zone/)?RS $0:FS $0}' file|awk '$1=$1'
zone: z_ABCSVR01_STORAGE1 ABCSVR; STORAGE1_P1; STORAGE_P2
zone: z_SUNSVR1_NBUSANCP SUNSVR1; NBUSANCP;
zone: z_WINSVR01_STORAGE2 WINSVR01; STORAGE1_P2; STORAGE_P3
使用awk
awk '{printf (/^zone/)?RS $0:FS $0}' file
zone: z_ABCSVR01_STORAGE1 ABCSVR; STORAGE1_P1; STORAGE_P2
zone: z_SUNSVR1_NBUSANCP SUNSVR1; NBUSANCP;
zone: z_WINSVR01_STORAGE2 WINSVR01; STORAGE1_P2; STORAGE_P3
或
如果需要删除无用的空白:
awk '{printf (/^zone/)?RS $0:FS $0}' file|awk '$1=$1'
zone: z_ABCSVR01_STORAGE1 ABCSVR; STORAGE1_P1; STORAGE_P2
zone: z_SUNSVR1_NBUSANCP SUNSVR1; NBUSANCP;
zone: z_WINSVR01_STORAGE2 WINSVR01; STORAGE1_P2; STORAGE_P3
如果您有
GNU awk
,这里还有另一种方法:
$ awk -v RS='zone:' '$1=$1' file
z_ABCSVR01_STORAGE1 ABCSVR; STORAGE1_P1; STORAGE_P2
z_SUNSVR1_NBUSANCP SUNSVR1; NBUSANCP;
z_WINSVR01_STORAGE2 WINSVR01; STORAGE1_P2; STORAGE_P3
如果您有
GNU awk
,这里还有另一种方法:
$ awk -v RS='zone:' '$1=$1' file
z_ABCSVR01_STORAGE1 ABCSVR; STORAGE1_P1; STORAGE_P2
z_SUNSVR1_NBUSANCP SUNSVR1; NBUSANCP;
z_WINSVR01_STORAGE2 WINSVR01; STORAGE1_P2; STORAGE_P3
在连接线时也删除空白
在连接行时也删除空白如果
GNU awk
可用,@jaypal简洁而优雅的解决方案就是最好的选择
这里有一个符合POSIX标准的解决方案,它试图在i和t之间打点(导致@jaypal的解决方案不符合标准的原因是使用了一个包含多个(文字)字符的RS
(记录分隔符)值):
- 它根据OP的请求从输出中删除
区域:
- 它不会在开头打印额外的
,也不会省略后面的一个\n
- 它使用带有格式参数的
安全地避免意外的控制字符。输入行中的扩展printf
如果
GNU awk
可用,@jaypal简洁而优雅的解决方案就是一条出路
这里有一个符合POSIX标准的解决方案,它试图在i和t之间打点(导致@jaypal的解决方案不符合标准的原因是使用了一个包含多个(文字)字符的RS
(记录分隔符)值):
- 它根据OP的请求从输出中删除
区域:
- 它不会在开头打印额外的
,也不会省略后面的一个\n
- 它使用带有格式参数的
安全地避免意外的控制字符。输入行中的扩展printf
要删除空白,请执行以下操作:
awk'{$1=$1;printf(/^zone/)?RS$0:FS$0}'文件
,该命令适用于关键字/^zone/
。但如果遵循规则,如前几个字符为空
,则无法删除空白。对于关键字/^zone/
,此命令可以执行:awk'{$1=$1;printf(/^zone/)?RS$0:FS$0}'文件
。但如果遵循规则,因为前几个字符是空的
,它就不能解释NR>1的用法是什么<代码>AWK-V RS=“区域”:“$ 1=1美元”文件< CygWin,在我的Env(CygWin)中,我没有看到空白行。“代码是正确的,<代码> { 1美元=1美元} 1 < /代码>将打印空白行,但是<代码> $1=$1 < /COD>不这样,因为它也隐含在布尔上下文中,如<代码> $1 {$1=$1;打印} <代码>(这是我的理解)。@AdrianFrühwirth谢谢,我不知道他的评论没有包括牙套。固定的!为了解释这一美妙之处:RS='zone:'
在出现zone:
之间,跨行将输入分解为记录$1=$1
触发基于OFS
的每个输入记录的重建(输出字段分隔符,默认为单个空格)-这就是合并行和(也将多个空格折叠为一个)的原因;在输出时,记录由ORS分隔,ORS默认为\n
。请参阅@AdrianFrühwirth的评论,了解为什么(根据需要)在开始时不打印空行,即使输入以区域开始:
(因此处理的第一条记录是空的)。NR>1
有何用途<代码>AWK-V RS=“区域”:“$ 1=1美元”文件< CygWin,在我的Env(CygWin)中,我没有看到空白行。“代码是正确的,<代码> { 1美元=1美元} 1 < /代码>将打印空白行,但是<代码> $1=$1 < /COD>不这样,因为它也隐含在布尔上下文中,如<代码> $1 {$1=$1;打印} <代码>(这是我的理解)。@AdrianFrühwirth谢谢,我不知道他的评论没有包括牙套。固定的!为了解释这一美妙之处:RS='zone:'
在出现zone:
之间,跨行将输入分解为记录$1=$1
触发基于OFS的每个输入记录的重建(输出字段分隔符,默认为单个空格)-这就是合并行和(也将多个空格折叠为一个)的原因;在输出时,记录由ORS分隔,ORS默认为\n
。请参阅@AdrianFrühwirth的评论,了解为什么(根据需要)在开始时不打印空行,即使输入以区域开始:
(因此处理的第一条记录为空)。
awk '
{
if ($1=="zone:") { # Zone lines
# Determine the separator to *precede* the output line:
# ORS, the output *record* separator, which defaults to \n
# - unless it is the very first line.
# Net effect: zone lines start new output lines.
sep=(notFirst++ ? ORS : "");
# Remove the `zone:` field by setting the first field,
# $1, to an empty string.
# Note: This causes the entire line to be rebuilt by joining the
# fields with OFS, the output field separator, which defaults
# to a space. Multiple adjacent space chars. are folded into
# one in the process.
$1="";
# Remove the space char. at the beginning of the rebuilt
# line that stems from setting $1 to an empty string.
$0=substr($0,2)
} else { # Non-zone lines
# Determine the separator to *precede* the output line:
# just the regular output *field* separator (space),
# effectively causing this line to be appended to the
# previous one.
sep=OFS;
# Trigger rebuilding the line so as to fold
# multiple adjacent space chars. into one.
$1=$1;
}
# Output the separator followed by the rebuilt line.
printf "%s%s", sep, $0
}
# Since the `printf` statement above never outputs
# a *terminating* \n, we output one at the very end.
END { print }
' file
sed ':a;$!N;/\nzone:/!s/\n\s*/ /;ta;s/^zone:\s*//;P;D' file