使用 bash 解析 ldapsearch 的输出

Using bash to parse the output of ldapsearch

我最近写了一个 bash 脚本,它必须解析 ldapsearch 结果的输出。该脚本有效,但我认为有更有效的方法来完成此操作。

该脚本执行一个 ldapsearch 命令,该命令以多行格式输出多条记录。每条记录由一个空行分隔。我最终做了以下事情:

  1. 在每行的末尾添加一个分隔符
  2. 将字符串'DELIM'添加到空白行
  3. 修剪所有新行
  4. 用新行替换了'DELIM'

这有效地将 ldapsearch 的多行输出转换为多行分隔值。然后我使用 cut 两次来解析行(一次分割分隔符,然后再次吐出 ldap 结果的输出)

代码如下:

while IFS= read -r line ; do
 dn=$(echo "$line" | cut -d '#' -f 1 | cut -d " " -f 2)
 uid=$(echo "$line" | cut -d '#' -f 2 | cut -d " " -f 2)
 uidNumber=$(echo "$line" | cut -d '#' -f 3 | cut -d " " -f 2)
 gidNumber=$(echo "$line" | cut -d '#' -f 4 | cut -d " " -f 2)

 # Code emitted since it's not relevant

done < <(ldapsearch -x -H "$ldap_server" -D 'cn=Directory Manager' -w $ds_password -b "$searchbase" -LLL uid uidNumber gidNumber | sed 's/$/#/g' | sed 's/^#$/DELIM/g' | tr -d '\n' | sed 's/DELIM/\n/g')

ldapsearch 命令的输出如下

dn: uid=userone,ou=People,dc=team,dc=company,dc=local
uid: userone
uidNumber: 5000
gidNumber: 5000

dn: uid=usertwo,ou=People,dc=team,dc=company,dc=local
uid: usertwo
uidNumber: 5001
gidNumber: 5001

有没有更有效的方法来完成这个?特别是一个不那么广泛使用管道的人?

你可以玩玩awk

ldap search | awk '=' RS= ORS='\n' OFS='#'
dn: uid=userone,ou=People,dc=team,dc=company,dc=local#uid: userone#uidNumber: 5000#gidNumber: 5000
dn: uid=usertwo,ou=People,dc=team,dc=company,dc=local#uid: usertwo#uidNumber: 5001#gidNumber: 5001

RS= 将记录选择器设置为空(将 awk 设置为块模式)(通常是每一行)
ORS='\n' 将输出记录选择器设置为新行
OFS='#' 将输出字段分隔符设置为 #
= 重新创建该行并打印它。

使用这个可能更安全:

awk '{=}1' RS= ORS='\n' OFS='#'

假设:

  • ldapsearch数据不包含白色space(s)
  • 将数据重新格式化为单行(通过 OP 的当前代码或通过 jotne 的回答)包括将 # 分隔符替换为 space ( )

使用 space(而不是 #)作为分隔符,我们得到以下重新格式化的 ldapsearch 数据(8x space 分隔字段):

dn: uid=userone,ou=People,dc=team,dc=company,dc=local uid: userone uidNumber: 5000 gidNumber: 5000
dn: uid=usertwo,ou=People,dc=team,dc=company,dc=local uid: usertwo uidNumber: 5001 gidNumber: 5001

可以修改 while read 操作以消除每次通过 while 循环时的(当前)12x 子进程调用 (4x $(echo|cut|cut)),例如:

while read -r _ dn _ uid _ uidNumber _ gidNumber
do
    echo "############"
    echo ".$dn."
    echo ".$uid."
    echo ".$uidNumber."
    echo ".$gidNumber."
done < <(ldapsearch ... | other_code_to_reformat_ldapsearch_data_as_single_lines_but_with_space_delimiter)

备注:

  • _ 是我们不关心的字段的虚拟占位符
  • 句点 (.) 添加到 echo 语句作为视觉分隔符

这会生成:

############
.uid=userone,ou=People,dc=team,dc=company,dc=local.
.userone.
.5000.
.5000.
############
.uid=usertwo,ou=People,dc=team,dc=company,dc=local.
.usertwo.
.5001.
.5001.

另一个 awk 重新格式化 ldapsearch 结果的想法,它只输出我们感兴趣的字段:

awk '{for (i=2;i<=NF;i=i+2) {printf (i==2 ? "" : " ") $i}; print ""}' RS= ORS='\n'

其中:

  • 我们重新使用 jotne 的 RS/ORS 设置
  • (i=2;i<=NF,i=i+2) - 只打印偶数字段

这会生成:

uid=userone,ou=People,dc=team,dc=company,dc=local userone 5000 5000
uid=usertwo,ou=People,dc=team,dc=company,dc=local usertwo 5001 5001

通过此更改(4x space 分隔字段而不是 8x space 分隔字段)建议的 while read 变为:

while read -r dn uid uidNumber gidNumber
do
    ....
done < <(ldapsearch ... | awk '{for (i=2;i<=NF;i=i+2) {printf (i==2 ? "" : " ") $i}; print ""}' RS= ORS='\n')