2

我正在 Mac OSX 10.11 上编写一个 bash 脚本,以便在我连接到我的 VPN 时自动使用 dns-sd 为 AFP、SMB 和一些打印机“代理”我的 Bonjour 广告。

我的脚本的基本要点是我声明了一些数组以供以后调用 dns-sd 时使用。我遇到困难的数组:

SERVICE_TEXTS=(
''
''
model=TimeCapsule8,119
model=Xserve
'txtvers=1 qtotal=1 pdl=application/vnd.hp-PCL,application/vnd.brother-hbp rp=duerqxesz5090 ty=Brother\ MFC-9120CN product=\(Brother MFC-9120CN\) adminurl=http://BRN001BA9243652.local./ priority=50 usb_MFG=Brother usb_MDL=MFC-9120CN Color=T Copies=T Duplex=F PaperCustom=T Binary=T Transparent=T TBCP=F'
'txtvers=1 qtotal=1 pdl=application/vnd.hp-PCL,application/vnd.brother-hbp rp=duerqxesz5090 ty="Brother MFC-9120CN" product="(Brother MFC-9120CN)" adminurl=http://BRN001BA9243652.local./ priority=75 usb_MFG=Brother usb_MDL=MFC-9120CN Color=T Copies=T Duplex=F PaperCustom=T Binary=T Transparent=T TBCP=F'
'txtvers=1 qtotal=1 pdl=application/vnd.hp-PCL,application/vnd.brother-hbp ty="Brother MFC-9120CN" product="(Brother MFC-9120CN)" adminurl=http://BRN001BA9243652.local./ priority=25 usb_MFG=Brother usb_MDL=MFC-9120CN Color=T Copies=T Duplex=F PaperCustom=T Binary=T Transparent=F TBCP=T'
)

要确定我是否需要实际运行 dns-sd,我会:

ifconfig ppp0 &>/dev/null

测试 ifconfig 的返回值:

if [ "$?" -eq "0" ]; then...

如果 ppp0 存在,我会遍历数组的长度,检查 dns-sd 当前是否正在运行,等等。

如果 dns-sd 实例一直在运行但 ppp0 现在不可用,我会通过保存的 PID 将它们全部杀死,并在几分钟后再次检查。

我相信我的其余代码正在执行我想要的,所以我会直接跳到有问题的行,希望总体思路足够清楚。

dns-sd -P "${SERVICE_NAMES[$n]}" "${SERVICE_TYPES[$n]}" local ${SERVICE_PORTS[$n]} "${SERVICE_NAMES[$n]}.local" "${SERVICE_IPS[$n]}" ${SERVICE_TEXTS[$n]} &>/dev/null &

为清楚起见,dns-sd 的手册页显示这是 -P 的用法。

dns-sd -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...]              (Proxy)

我面临的问题是最后三个 SERVICE_TEXTS 元素中空格字符的行为。到目前为止,故障排除一直是在终端中做所有事情,以确保我没有遗漏一些非常明显/发疯的东西。这正是我输入的内容以及返回的内容......哪个有效

$ dns-sd -P "Brother MFC-9129CN" _ipp._tcp local 631 "Brother MFC-9120CN.local" 192.168.1.2 txtvers=1 qtotal=1 pdl=application/vnd.hp-PCL,application/vnd.brother-hbp rp=duerqxesz5090 ty=Brother\ MFC-9120CN product=\(Brother\ MFC-9120CN\) adminurl=http://BRN001BA9243652.local./ priority=50 usb_MFG=Brother usb_MDL=MFC-9120CN Color=T Copies=T Duplex=F PaperCustom=T Binary=T Transparent=T TBCP=F

Registering Service Brother MFC-9129CN._ipp._tcp.local host Brother MFC-9120CN.local port 631 TXT txtvers=1 qtotal=1 pdl=application/vnd.hp-PCL,application/vnd.brother-hbp rp=duerqxesz5090 ty=Brother\ MFC-9120CN product=\(Brother\ MFC-9120CN\) adminurl=http://BRN001BA9243652.local./ priority=50 usb_MFG=Brother usb_MDL=MFC-9120CN Color=T Copies=T Duplex=F PaperCustom=T Binary=T Transparent=T TBCP=F
DATE: ---Sat 03 Oct 2015---
21:11:40.927  ...STARTING...
21:11:41.818  Got a reply for record Brother MFC-9120CN.local: Name now registered and active
21:11:41.818  Got a reply for service Brother MFC-9129CN._ipp._tcp.local.: Name now registered and active

但是,当我在命令中使用变量时(为清楚起见,回显)...发生这种情况

$ echo ${SERVICE_TEXTS[4]}
txtvers=1 qtotal=1 pdl=application/vnd.hp-PCL,application/vnd.brother-hbp rp=duerqxesz5090 ty=Brother\ MFC-9120CN product=\(Brother MFC-9120CN\) adminurl=http://BRN001BA9243652.local./ priority=50 usb_MFG=Brother usb_MDL=MFC-9120CN Color=T Copies=T Duplex=F PaperCustom=T Binary=T Transparent=T TBCP=F

$ dns-sd -P "Brother MFC-9129CN" _ipp._tcp local 631 "Brother MFC-9120CN.local" 192.168.1.2  ${SERVICE_TEXTS[4]}

Registering Service Brother MFC-9129CN._ipp._tcp.local host Brother MFC-9120CN.local port 631 TXT txtvers=1 qtotal=1 pdl=application/vnd.hp-PCL,application/vnd.brother-hbp rp=duerqxesz5090 ty=Brother\\\\ MFC-9120CN product=\(Brother MFC-9120CN\) adminurl=http://BRN001BA9243652.local./ priority=50 usb_MFG=Brother usb_MDL=MFC-9120CN Color=T Copies=T Duplex=F PaperCustom=T Binary=T Transparent=T TBCP=F
DATE: ---Sat 03 Oct 2015---
21:18:56.968  ...STARTING...
21:18:57.842  Got a reply for record Brother MFC-9120CN.local: Name now registered and active
21:18:57.842  Got a reply for service Brother MFC-9129CN._ipp._tcp.local.: Name now registered and active

问题是元素4的部分

"...ty=Brother\ MFC..."

dns-sd 报告这是

"...ty=Brother\\\\ MFC..."

您会注意到,当我只是键入字符串而不是使用变量时,dns-sd 会用一个“\”报告它。

显然四个“\”对我没有任何好处......如果我删除“\”,我仍然没有得到想要的结果,因为 dns-sd 认为我正在描述一个新密钥。我打字

"\\"

尝试获取文字“\”,并且从内存中 dns-sd 仍然收到四个。

我也玩过单引号和双引号,包括在对 dns-sd 的调用中将变量括在双引号中,但这会在每个空格中添加反斜杠。这使得 dns-sd 将 TXT 字符串视为一键一值,其中值包含空格。这比不带引号调用它的用处要小得多,所以我放弃了进一步调查。

所以基本上,似乎 dns-sd 没有收到或收到四个“\”......它只需要一个然后一切都会完美运行......

调用 dns-sd 并传递不带引号的 ${SERVICE_TEXTS[$n]} 非常接近所需的行为,但无法处理键值对的“值”中的空格字符。

这里的任何指导将不胜感激!我一直在翻阅 bash 手册,搜索堆栈交换并尝试我能想到的一切以使这项工作持续 4 小时 :(

4

1 回答 1

1

所以在博主的帮助下,我得到了这个脚本的灵感,问题就解决了。

这确实是一个引用问题,因此我认为这似乎是无休止的实验,导致不同程度的成功。

就像庇护所建议的那样,这是 dnd-sd 收到类似"key=value key=value with spaces"而不是key=value key="value with spaces" key=valueWithoutSpaces

我面临的问题是很难看到将在我的脚本中执行的 EXACT 命令,因为 dns-sd 似乎也对它自己做了一些转义。从这里开始,更容易确定将我的精力集中在哪里进行引用。

所以要检查这个,有人建议我使用这样的东西

#FIX: by using a temporary variable we can debug the exact command that will be used including all quotes
CMD="dns-sd -P \"${SERVICE_NAMES[$n]}\" ${SERVICE_TYPES[$n]} local ${SERVICE_PORTS[$n]} \"${SERVICE_NAMES[$n]}.local\" \"${SERVICE_IPS[$n]}\" ${SERVICE_TEXTS[$n]} &>/dev/null &"
echo "DEBUG: $CMD"

# use exactly this command 
eval $CMD
PIDS[$n]=$!;

以及产生的 SERVICE_TEXT[4] 键有效

'txtvers=1 qtotal=1 pdl=application/vnd.hp-PCL,application/vnd.brother-hbp rp=duerqxesz5090 ty="Brother MFC-9120CN" product="(Brother MFC-9120CN)" adminurl=http://BRN001BA9243652.local./ priority=50 usb_MFG=Brother usb_MDL=MFC-9120CN Color=T Copies=T Duplex=F PaperCustom=T Binary=T Transparent=T TBCP=F'

根据您使用的转义空格机制,dns-sd 期望转义括号并没有帮助;如果您键入\[space]以逃避 avalue with spaces它希望您也逃避括号。但是引用整个事情会导致 dns-sd 自己处理括号......

所以我要从中得到的信息是创建一个临时变量来显示变量扩展,在评估它之前对其进行回显以指导搜索不稳定的引号。

于 2015-10-04T10:05:26.170 回答