我想搜索文件中的行范围,这些行以start开头并以End结尾,并用冒号替换换行符 . 我需要在SED或AWK中完成此操作 .
示例文件:
start a b c End Start a b c End Start x y z End
预期产出:
a:b:c a:b:c x:y:z
这个短awk单行应该工作:
awk -v RS='Start|End' -v OFS=":" '$1=$1' file
与您的数据:
kent$ cat f Start a b c End Start a b c End Start x y z End kent$ awk -v RS='Start|End' -v OFS=":" '$1=$1' f a:b:c a:b:c x:y:z
这是一个版本:
awk '/End/{print a;f=a=0} f {a=a?a":"$0:$0} /(S|s)tart/{f=1}' file a:b:c a:b:c x:y:z
我猜第一个 start 中有一个拼写错误,如果是这样的话:
start
awk '/End/{print a;f=a=0} f {a=a?a":"$0:$0} /Start/{f=1}' file
/End/{print a;f=a=0} 如果行包含 End print a ,并将 f 和 a 设置为 0f {a=a?a":"$0:$0} 如果 f 为真,则首次运行时将 a 设置为 $0 ,下次运行时设置为 :$0/Start/{f=1} 如果行有 Start 设置 f 到 1 (真)
/End/{print a;f=a=0}
End
a
f
0
f {a=a?a":"$0:$0}
$0
:$0
/Start/{f=1}
Start
1
让我们试试 awk .
awk
$ awk '/start/ || /Start/ {next} /End/ {print line; line=""; next} {if (line) {line=line":"} line=line$0}' file a:b:c a:b:c x:y:z
/start/ || /Start/ {next} 在包含"start"或"Start"的行上,跳过 .
/start/ || /Start/ {next}
/End/ {print line; line=""; next} 在包含 End 的行上,打印包含已加载信息的 line 变量 . 删除var的值并转到下一行 .
/End/ {print line; line=""; next}
line
{if (line) {line=line":"} line=line$0} 在其余行上,继续在 line 变量中加载数据 . if 条件是为了避免尾随 : .
{if (line) {line=line":"} line=line$0}
if
:
/start/ || /Start/ {next} 可以缩减为这两个(thanks Jotne):
/start|Start/ {next} /(s|S)tart/ {next}
如果开始和结束之间总共有3行:
grep -iv 'start\|end' file | paste -d: - - -
sed -n '/Start/,/End/ { /Start/ !{ /End/ !H } /End/ { s/.*// x s/\n/:/g s/:// p } } /Start/,/End/ !p' YourFile
如果 start 和 Start 应该在代码中用 [sS]tart 替换 Start (和 /start/ || /Start/ {next} 由 [eE]nd )
[sS]tart
[eE]nd
Explaination
除非特定要求,否则在不打印输出的情况下启动sed
/Start/,/End/ {
对于以 Start 开头并以 End 结尾的任何行块(在单独的行上)
/Start/ !{ /End/ !H }
如果行不包含( ! ) Start 而不是 End ,则将该行添加(追加)到保持缓冲区(存储类型)
!
/End/ { s/.*// x s/\n/:/g s/:// p }
到达包含 End 的行时
删除当前行( End )
交换( x )保持缓冲区(存储了所有行的行)和工作缓冲区(可以操作且通常具有当前行的缓冲区)
x
用 : 更改所有新行(缓冲区包含交换后新行分隔的所有行)
首先删除 : (由于首先添加插入新行)
打印内容
/开始/,/结束/!p
对于 Start 和 End 之间的块之间的所有行( ! ),打印出来
只是GNU awk的另一种方法:
$ gawk -v RS='\0' '{ gsub(/\n/,":"); gsub(/:End:Start:/,"\n"); gsub(/^start:|:End:$/,"") }1' file a:b:c a:b:c x:y:z
这里发布的其他awk解决方案也很好 .
6 回答
这个短awk单行应该工作:
与您的数据:
这是一个版本:
我猜第一个
start
中有一个拼写错误,如果是这样的话:/End/{print a;f=a=0}
如果行包含End
printa
,并将f
和a
设置为0
f {a=a?a":"$0:$0}
如果f
为真,则首次运行时将a
设置为$0
,下次运行时设置为:$0
/Start/{f=1}
如果行有Start
设置f
到1
(真)让我们试试
awk
.解释
/start/ || /Start/ {next}
在包含"start"或"Start"的行上,跳过 ./End/ {print line; line=""; next}
在包含End
的行上,打印包含已加载信息的line
变量 . 删除var的值并转到下一行 .{if (line) {line=line":"} line=line$0}
在其余行上,继续在line
变量中加载数据 .if
条件是为了避免尾随:
./start/ || /Start/ {next}
可以缩减为这两个(thanks Jotne):如果开始和结束之间总共有3行:
如果 start 和
Start
应该在代码中用[sS]tart
替换Start
(和/start/ || /Start/ {next}
由[eE]nd
)Explaination
除非特定要求,否则在不打印输出的情况下启动sed
对于以
Start
开头并以End
结尾的任何行块(在单独的行上)如果行不包含(
!
)Start
而不是End
,则将该行添加(追加)到保持缓冲区(存储类型)到达包含
End
的行时删除当前行(
End
)交换(
x
)保持缓冲区(存储了所有行的行)和工作缓冲区(可以操作且通常具有当前行的缓冲区)用
:
更改所有新行(缓冲区包含交换后新行分隔的所有行)首先删除
:
(由于首先添加插入新行)打印内容
/开始/,/结束/!p
对于
Start
和End
之间的块之间的所有行(!
),打印出来只是GNU awk的另一种方法:
这里发布的其他awk解决方案也很好 .