正确的字符串转义策略

Proper escape strategy for strings

我正在编写一个简单的 BASH 脚本来生成一个 LDIF 文件,然后我可以使用该文件将用户添加到我的 OpenLDAP 服务器。

这是脚本:

#!/bin/bash
#add LDAP user, v1.0, by mbobak, 11/17/2020
if [ $# != 6 ];
then
    echo "`basename [=10=]`:  error:  invalid number of arguments:"
        echo "`basename [=10=]` <userid> <firstname> <lastname> <gidnum> <uidnum> <empno>"
    exit 1
fi
userid=
firstname=
lastname=
gidnum=
uidnum=
empno=
temppasswd=`slappasswd -s pw4${userid}`
echo ${userid} ${firstname} ${lastname} ${gidnum} ${uidnum} ${empno} ${temppasswd}
sed -e "s/#userid#/${userid}/g" -e "s/#gidnum#/${gidnum}/g" -e "s/#firstname#/${firstname}/g" -e "s/#lastname#/${lastname}/g" -e "s/#uidnum#/${uidnum}/g" -e "s/#empno#/${empno}/g" -e "s/#temppasswd#/${temppasswd}/g" user_tmpl.ldif

我将它与此模板一起使用:

dn: uid=#userid#,ou=people,dc=nitssolutions,dc=com
objectClass: top
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: #userid#
gidNumber: #gidnum#
givenName: #firstname#
sn: #lastname#
displayName: #firstname# #lastname#
homeDirectory: /home/#userid#
mail: #userid#@nitssolutions.com
loginShell: /bin/bash
cn: #firstname# #lastname#
uidNumber: #uidnum#
employeeType: INT-FT
employeeNumber: #empno#

dn: uid=#userid#,ou=people,dc=nitssolutions,dc=com
changetype: modify
add: userPassword
userPassword: #temppasswd#

这似乎工作得很好,除了 slappasswd 的输出包含 / 字符时。

发生这种情况时,我收到以下错误:

./add_ldap_user.sh jdoe John Doe 123456 123456 NS1234
jdoe John Doe 123456 123456 NS1234 {SSHA}kTwHVDBiK4ub3laqwaqZpAUwILrW/Vw9
sed: -e expression #7, char 51: unknown option to `s'

同样,只有当 slappasswd 的输出包含 /.

时才会发生这种情况

我确定我在这里遗漏了一些简单的东西,但我不清楚正确答案是什么。我不能简单地转义整个表达式,否则我的变量将恢复为静态字符串“${temppasswd}”,这无济于事。我需要 ${temppasswd} 的值,即使它包含需要转义的字符。

帮忙?

this only happens when the output of slappasswd contains a /.

选择不同的 s 命令分隔符。像 ~ 或任何其他字符。

sed -e "s~#userid#~${userid}~g"

在 GNU sed 的边缘情况下,您可以使用 any 字节,例如,您可以使用 C 转义 $'\x01' 来写入 0x01 字节:

sed -e $'s\x01#userid#\x01'"${userid}"$'\x01g'

但我建议不要重新发明轮子并使用现有的模板工具。将模板格式从 #userid# 更改为 ${userid},您可以使用 envsubst.

使用 envsubst 和以下重新设计的模板:

dn: uid=${userid},ou=people,dc=nitssolutions,dc=com
objectClass: top
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: ${userid}
gidNumber: ${gidnum}
givenName: ${firstname}
sn: ${lastname}
displayName: ${firstname} ${lastname}
homeDirectory: /home/${userid}
mail: ${userid}@nitssolutions.com
loginShell: /bin/bash
cn: ${firstname} ${lastname}
uidNumber: ${uidnum}
employeeType: INT-FT
employeeNumber: ${empno}

dn: uid=${userid},ou=people,dc=nitssolutions,dc=com
changetype: modify
add: userPassword
userPassword: ${temppasswd}

已处理:program1

#!/usr/bin/env bash

Iam="${0##*/}" # Basename of myself
if [ $# -ne 6 ];
  cat <<ERR >&2
$Iam:  error:  invalid number of arguments:

Usage:
$Iam <userid> <firstname> <lastname> <gidnum> <uidnum> <empno>
ERR
  exit 1
fi

userid="" firstname="" lastname="" \
gidnum="" uidnum="" empno="" \
temppasswd=$(slappasswd -s "pw4$userid") \
envsubst <user_tmpl.ldif

使用虚拟值测试 运行:

./program1 foo bar baz 666 42 99
foo bar baz 666 42 99 ciWatEpIcs

输出

dn: uid=foo,ou=people,dc=nitssolutions,dc=com
objectClass: top
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: foo
gidNumber: 666
givenName: bar
sn: baz
displayName: bar baz
homeDirectory: /home/foo
mail: foo@nitssolutions.com
loginShell: /bin/bash
cn: bar baz
uidNumber: 42
employeeType: INT-FT
employeeNumber: 99

dn: uid=foo,ou=people,dc=nitssolutions,dc=com
changetype: modify
add: userPassword
userPassword: ciWatEpIcs

现在有了一个简单的here文档,它甚至不需要envsubst

program2:

#!/usr/bin/env bash

Iam="${0##*/}" # Basename of myself
if [ $# -ne 6 ];
then
  cat <<ERR >&2
$Iam:  error:  invalid number of arguments:

Usage:
$Iam <userid> <firstname> <lastname> <gidnum> <uidnum> <empno>
ERR
  exit 1
fi
userid=
firstname=
lastname=
gidnum=
uidnum=
empno=
temppasswd=$(slappasswd -s "pw4$userid")

cat <<LDIFTEMPLATE
dn: uid=${userid},ou=people,dc=nitssolutions,dc=com
objectClass: top
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: ${userid}
gidNumber: ${gidnum}
givenName: ${firstname}
sn: ${lastname}
displayName: ${firstname} ${lastname}
homeDirectory: /home/${userid}
mail: ${userid}@nitssolutions.com
loginShell: /bin/bash
cn: ${firstname} ${lastname}
uidNumber: ${uidnum}
employeeType: INT-FT
employeeNumber: ${empno}

dn: uid=${userid},ou=people,dc=nitssolutions,dc=com
changetype: modify
add: userPassword
userPassword: ${temppasswd}
LDIFTEMPLATE