我有一个包含一堆证书的文件:
-----BEGIN CERTIFICATE-----
AAAAAAA
AAAAAAA
AAAAAAA
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
BBBBBBB
BBBBBBB
BBBBBBB
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
CCCCCCC
CCCCCCC
CCCCCCC
-----END CERTIFICATE-----
A
我想把里面写的那张砍掉,只得到B
C
……n
证书。
它非常类似于这个问题我希望有一种便携的方式来做到这一点。sed
如果可能的话最好使用 with ,但awk
如果不可能使用 ,也可以使用sed
。
有没有办法让 sed 打印直到除了第一次出现之外的特定值?
答案1
如果您的输入是格式良好的证书文件(如示例所示),那么我想到的最简单的方法是使用以下命令awk
:
awk '$0=="-----BEGIN CERTIFICATE-----" {n++} n>1' test.cert
n
每当当前行 ( $0
) 与“起始模式”完全匹配时,这都会增加一个计数器变量。如果“看似杂散”的布尔表达式n>1
为真,即从第二次出现的起始模式开始,它将打印当前行。awk
将未初始化的变量视为零(或空字符串,具体取决于使用上下文),因此无需在节中显式n
初始化。0
BEGIN
如果您的输入文档可能被损坏,即包含与结束模式不正确匹配的开始模式,则事情会变得更加复杂,反之亦然。
答案2
@AdminBee 答案是正确的方法,但是如果您确定要省略的部分是第一的sed
你也可以这样做:
sed -n '/^-*END CERTIFICATE-*$/!d;:a n;p;ba' file
或者以多线便携式方式:
sed -n '
/^-*END CERTIFICATE-*$/!d;:a
n;p;ba
' file
这sed
将删除所有行,直到找到第一行-----END CERTIFICATE-----
,然后创建一个循环,该循环将吃掉并打印所有其他行。
答案3
您应该将正则表达式 /BEGIN/ 和 /END/ 更改为必需的。
awk '
/BEGIN/,/END/{
if ( /END/ && !f++ ) next
}f
' file
perl
处于吸食模式 ( -0777
)
perl -0777 -pe '
my($b,$e) = map { quotemeta s/$/ CERTIFICATE/r } qw(BEGIN END);
my($B,$E) = map { qr{^-+ $_ -+\n}mx } ($b,$e);
my $re = qr{$B (?s:.*?) $E}mx;
substr($_,0,$+[0],"") if m{$re}m;
' file
GNU sed 编辑器
sed -ne 's/\n//;t2
/BEGIN/!{$!N;D;}
:1;n;/END/!b1
n
:2;$!{N;P;G;D;}
p
' file
csplit
此处也可以使用linux 实用程序。我们首先在 END 行周围对输入文件进行分块。然后删除第一个文件或前两个文件,以防 END 出现在 BEGiN 之前。
csplit -sz file '/END/+1' '{*}'
for f in xx*;do
sed -n '/BEGIN/,/END/!d;$Q1' $f
status=$?; rm -- "$f"
[ " $status" = ' 1' ] && break
done
printf '%s\n' xx* | xargs -r cat