3

我有一个证书存储在单行的环境变量中,如下所示:

$EXAMPLE=-----BEGIN CERTIFICATE----- line1 line2 line3 etc.. -----END CERTIFICATE-----

我怎样才能从这个环境变量转到一个文件,其中的行都转换为换行符,除了 -----BEGIN CERTIFICATE----- 和 -----END CERTIFICATE----- 部分?

我知道我可以这样做:

$ echo "$EXAMPLE" | tr ' ' '\n' > ca.pem

它将所有空格替换为换行符,但这将导致:

-----BEGIN
CERTIFICATE-----
line1
line2
line3
etc..
-----END
CERTIFICATE-----

快到了...但是带有'-----'的 BEGIN 和 END 行不应该中断。有人对此有干净的解决方案吗?不管它是 sed、awk、grep 还是其他的 :)

谢谢!

4

4 回答 4

3

不要将所有大写字母用于非导出的变量名,以避免与导出的和/或内置的名称冲突。使用 GNU awk 将第三个 arg 用于 match() 并\S使用简写[^[:space:]]

$ example='-----BEGIN CERTIFICATE----- line1 line2 line3 -----END CERTIFICATE-----'
$ printf '%s\n' "$example" |
awk 'match($0,/^(\S+ \S+)(.*)(\S+ \S+)$/,a){gsub(/ /,ORS,a[2]); print a[1] a[2] a[3]}'
-----BEGIN CERTIFICATE-----
line1
line2
line3
-----END CERTIFICATE-----

上面的脚本适用于任何输入。您应该尝试提出脚本可能失败的输入,以便能够测试任何建议的解决方案,以查看它是否真的有效,因为提出一个从一个特定示例输入产生预期输出的脚本很简单,并且想出一个适用于所有情况的解决方案要困难得多。

例如,一个重要且明显的测试示例是:

$ example='-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE----- -----END CERTIFICATE----- -----END CERTIFICATE-----'

即,在 4 行证书本身中恰好巧合/不幸的是这些字符串:

  • 第 1 行 =-----BEGIN
  • 第 2 行 =CERTIFICATE-----
  • 第 3 行 =-----END
  • 第 4 行 =CERTIFICATE-----

输出应该是:

$ printf '%s\n' "$example" |
awk 'match($0,/^(\S+ \S+)(.*)(\S+ \S+)$/,a){gsub(/ /,ORS,a[2]); print a[1] a[2] a[3]}'
-----BEGIN CERTIFICATE-----
-----BEGIN
CERTIFICATE-----
-----END
CERTIFICATE-----
-----END CERTIFICATE-----

因此,如果任何建议的解决方案都无法正确处理,请不要使用该解决方案。

当前发布的其他答案均未正确处理:

拉文德的 awk:

$ printf '%s\n' "$example" |
awk '
match($0,/- .* -/){
  val=substr($0,RSTART,RLENGTH)
  gsub(/- | -/,"",val)
  gsub(OFS,ORS,val)
  print substr($0,1,RSTART) ORS val ORS substr($0,RSTART+RLENGTH-1)
}'
-----BEGIN CERTIFICATE-----
-----BEGIN
CERTIFICATE---------END
CERTIFICATE-----
-----END CERTIFICATE-----

saichovsky 的 seds 加管:

$ printf '%s\n' "$example" |
sed 's/- /-\n/g; s/ -/\n-/g' | sed '/CERTIFICATE/! s/ /\n/g'
-----BEGIN CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
-----END CERTIFICATE-----

anubhava 的 perl:

$ perl -pe 's/(?:BEGIN|END) CERTIFICATE(*SKIP)(*F)|\h+/\n/g' <<< "$example"
-----BEGIN CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
-----END CERTIFICATE-----
于 2018-12-09T16:55:12.993 回答
2

使用perl您可以使用正则表达式(*SKIP)(*F)

s='-----BEGIN CERTIFICATE----- line1 line2 line3 -----END CERTIFICATE-----'
perl -pe 's/-+(?:BEGIN|END) CERTIFICATE-+(*SKIP)(*F)|\h+/\n/g' <<< "$s"

-----BEGIN CERTIFICATE-----
line1
line2
line3
-----END CERTIFICATE-----

正则表达式将在匹配 1+ 个水平空格以被换行符替换时...(*SKIP)(*F)|\h+跳过开始-BEGIN CERTIFICATE-或结束。-END CERTIFICATE-


如果perl这里没有可用的awk解决方案(有点冗长,因为我想让它也可以在非 GNU awk 上工作):

awk '{
   out=""
   for (i=1; i<=NF; i++)
      out = sprintf("%s%s%s", out, $i, 
      (i<NF && $i~/^-+(BEGIN|END)$/ && $(i+1)~/^CERTIFICATE-+$/ ? " " : "\n"))
   printf "%s", out
}' <<< "$s"
于 2018-12-09T16:50:09.657 回答
0

您能否尝试一次(考虑到您的 Input_file 与显示的示例相同)。

EXAMPLE="-----BEGIN CERTIFICATE----- line1 line2 line3 -----END CERTIFICATE-----"
echo "$EXAMPLE" | awk '
match($0,/- .* -/){
  val=substr($0,RSTART,RLENGTH)
  gsub(/- | -/,"",val)
  gsub(OFS,ORS,val)
  print substr($0,1,RSTART) ORS val ORS substr($0,RSTART+RLENGTH-1)
}'


说明:现在添加对上述代码的说明。

echo "$EXAMPLE" | awk '          ##Printing value of example variable and passing its output to awk command then.
match($0,/- .* -/){              ##using match to match REGEX to match it from - .* to - if match found then do following.
  val=substr($0,RSTART,RLENGTH)  ##creating val here whose value is substring is starting from RSTART to RLENGTH.
  gsub(/- | -/,"",val)           ##Using gsub to substitute to substitute - space OR space - with NULL in variable val.
  gsub(OFS,ORS,val)              ##Substituting OFS with ORS in variable val here.
  print substr($0,1,RSTART) ORS val ORS substr($0,RSTART+RLENGTH-1)  ##Printing substring from 1 to RSTART then val and substring RSTART+RLENGTH-1 with ORS values.
}'
于 2018-12-09T17:02:45.607 回答
-2
echo $EXAMPLE | sed 's/- /-\n/g; s/ -/\n-/g' | sed '/CERTIFICATE/! s/ /\n/g'

应该给你你想要的。

于 2018-12-09T17:02:09.823 回答