我在输入文件中有以下内容
#Start para
0 hello dq
1 world dq
2 welcomes dq
3 you dq
#Start para
0 how tq
1 are tq
2 you tq
#Start para
0 say dq
1 hello dq
2 to dq
3 the dq
4 world dq
我希望将其定向到另一个文件,如下所示
#Start para
3 you dq
2 welcomes dq
1 world dq
0 hello dq
#Start para
2 you tq
1 are tq
0 how tq
#Start para
4 world dq
3 the dq
2 to dq
1 hello dq
0 say dq
我该如何使用sed
or来做到这一点awk
?基本上我想要反转的段落#Start para
。但段落的顺序应保持不变。
答案1
如果唯一的#
是块的开头那么awk
你可以尝试
$ awk -F'\n' 'BEGIN{RS="#"}NR>1{print "#"$1;for(i=NF-1;i>1;i--)print $i}' file
结果:
#Start para
3 you dq
2 welcomes dq
1 world dq
0 hello dq
#Start para
2 you tq
1 are tq
0 how tq
#Start para
4 world dq
3 the dq
2 to dq
1 hello dq
0 say dq
答案2
和sed
:
sed '/#Start para/{x;G;s/^\n//;p;s/.*//;x;d};G;s/\n$//;h;$!d' input.file
对于包含以下内容的行,将其附加到by e更改#Start para
的末尾:hold space
x
模式空间<->保留空间然后返回数据抓住将G
其附加到图案。 (同样可以通过H
(附加到保持)然后通过返回到模式来完成g
)。如果保留空间为空,则模式空间将从空行开始,因此它会被删除s/^\n//
并p
打印收集的行。下一个命令(直到}
)旨在清理保留和模式空间并转到下一行。
对于其他行(不包含#Start para
),将G
保留空间附加到模式,删除空行(如果保留空间为空),然后将模式空间放入保留并开始新循环,d
如果不是最后一行,则删除所有内容。如果是最后一行,则默认打印形成的图案空间。
答案3
对于更保守、更少神秘的方法......
awk '
/^#/ { printf "%s",out ; print ; out = "" }
/^[0-9]/ { out = $0 RS out }
END { printf "%s",out }
'
答案4
这里有一个三管齐下的方法:
sed 's/^#/\n#/' file |
perl -00lne '@A=split(/\n/); print shift(@A); print join "\n", reverse @A' |
grep .
解释
- 该
sed
命令在以 . 开头的每行之前添加一个换行符#
。这使我们能够使用 Perl 的段落模式(见下文)。 Perl 选项:
-00
激活“段落模式”,“行”由 2 个字符定义\n
。-l
:删除尾随换行符并\n
在每个print
调用中添加 a 。-n
:逐行(或在本例中逐段)读取输入文件。-e
:将在每行运行的脚本。
Perl 脚本:
@A=split(/\n/);
:将此行(段落)拆分到数组中@A
,使每个单独的行(这里是真正的行,而不是段落)成为数组的一个元素。print shift(@A);
@A
:删除(标题行)的第一个元素并打印它。print join "\n", reverse @A'
:将 的其余元素反转@A
,用字符连接\n
并打印。
grep .
:只是一个肮脏的黑客行为,删除了添加的空白行sed
。这将打印包含至少一个字符的所有行。