【问题标题】:Split String with a word delimiter into array in bash将带有单词分隔符的字符串拆分为bash中的数组
【发布时间】:2019-09-24 19:43:18
【问题描述】:

我有一个如下字符串:

dn: uid=svc_ddvportal2ssh,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_ddvportal2ssh svc_ddvportal2ssh krbpasswordexpiration: 20180607182429Z dn: uid=svc_ddvrundeckdeploy,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_ddvrundeckdeploy svc_ddvrundeckdeploy krbpasswordexpiration: 20180607182430Z dn: uid=svc_bo2ansible_mon,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_bo2ansible_mon svc_bo2ansible_mon krbpasswordexpiration: 20990101200000Z

想像下面这样提取到数组a中

a[0] = dn: uid=svc_bo2icinga2ipa,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_bo2icinga2ipa svc_bo2icinga2ipa krbpasswordexpiration: 20180119194104Z
a[1] = dn: uid=svc_ddvrundeckdeploy,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_ddvrundeckdeploy svc_ddvrundeckdeploy krbpasswordexpiration: 20180607182430Z
a[2] = uid=svc_bo2ansible_mon,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_bo2ansible_mon svc_bo2ansible_mon krbpasswordexpiration: 20990101200000Z 

我尝试使用IFS 分隔符但没有成功。请有人帮我解决这个问题

【问题讨论】:

  • 具体来说,哪个词是分隔符?您能否构建更短/更易于阅读的示例数据,使您想要的逻辑更加明显? (minimal reproducible example 规则不仅仅适用于代码)。
  • 为什么a[2] 值上没有dn: 前缀?
  • 我怀疑输入字符串中不存在换行符。
  • @JNevill, ...什么换行?我在问题的文字中看不到任何内容;它只是在单个反引号中允许浏览器完成换行,因此人们实际上可以读取输入数据而无需从左到右滚动。
  • a[2] 也包含 dn 元素。错字。

标签: string bash split


【解决方案1】:

使用 GNU sed 构建您的数组:

mapfile -t a < <(sed -r 's/ .{14}Z /&\n/g' file)

见:The Stack Overflow Regular Expressions FAQ

【讨论】:

  • 也许添加一个 readarraymapfile 消耗该 sed 命令的输出,因为 OP 想要填充一个数组?
  • 顺便说一句,我很好奇我们谁是对的。猜测 OP 的预期分隔符——你在Zs 之后停止,我从dn: 开始。 (顺便说一句,也许将其从 .{14} 更改为 [[:digit:]]{14}?)
【解决方案2】:

这是可行的,是的。如果您不介意颠倒数组的顺序,最简单的方法如下所示:

s='dn: uid=svc_ddvportal2ssh,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_ddvportal2ssh svc_ddvportal2ssh krbpasswordexpiration: 20180607182429Z dn: uid=svc_ddvrundeckdeploy,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_ddvrundeckdeploy svc_ddvrundeckdeploy krbpasswordexpiration: 20180607182430Z dn: uid=svc_bo2ansible_mon,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_bo2ansible_mon svc_bo2ansible_mon krbpasswordexpiration: 20990101200000Z'

while [[ $s =~ (.*)(dn: .*) ]]; do
  results+=( "${BASH_REMATCH[2]}" )
  s=${BASH_REMATCH[1]}
done
declare -p results # print the resulting array

...作为输出发出(添加换行符以提高可读性):

declare -a results='(
  [0]="dn: uid=svc_bo2ansible_mon,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_bo2ansible_mon svc_bo2ansible_mon krbpasswordexpiration: 20990101200000Z"
  [1]="dn: uid=svc_ddvrundeckdeploy,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_ddvrundeckdeploy svc_ddvrundeckdeploy krbpasswordexpiration: 20180607182430Z "
  [2]="dn: uid=svc_ddvportal2ssh,cn=users,cn=accounts,dc=tenant,dc=ycsdev,dc=io cn: svc_ddvportal2ssh svc_ddvportal2ssh krbpasswordexpiration: 20180607182429Z "
)'

相比之下,如果您愿意牺牲性能来保留原始顺序,请将results+=( "${BASH_REMATCH[2]}" ) 更改为results=( "${BASH_REMATCH[2]}" "${results[@]}" )


我们在这里所做的是匹配从后到前的序列(因为 bash 没有非贪婪的正则表达式,第一个 .* 匹配所有 last @ 987654326@).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-24
    • 2021-09-07
    • 2014-11-28
    • 1970-01-01
    • 2011-10-23
    相关资源
    最近更新 更多