zsh
如果我使用和运行下面的脚本bash
,我会得到不同的结果。有趣的是,这是由\n
输入字符串中的换行符引起的。
使用zsh
,我得到正确的结果:
rene@MININT-G1P7G69 Desktop % zsh bash_vs_zsh.sh
Hashed signature: AgTW6P8HlAlfOikDPMa/Q92tX2a0GSdDLVeeZE219BQ=
有了bash
,我得到了一个不正确哈希(hash):
rene@MININT-G1P7G69 Desktop % bash bash_vs_zsh.sh
Hashed signature: R2FaEYqGsb9QtCQTJEvySoqs0VEgtCyWEWg1R5jRzEo=
如果我\n
从输入中删除实例,结果是相等的。
signature="get\ndbs\n\nmon, 27 apr 2020 16:11:57 gmt\n\n"
masterKey="t7ejJOwk0HEgkeYCm9v3n8vNwVaW27uriUmTTc3JcBtwqHBfwqO1tAJqKOBpeivurzPl1DxsNFUehEQN5lzGRw=="
hashedSignature=$(echo -n $signature | openssl dgst -sha256 -mac hmac -macopt hexkey:$(echo -n $masterKey | base64 --decode | hexdump -v -e '/1 "%02x"') -binary | base64)
echo "Hashed signature: $hashedSignature"
我怎样才能让其bash
表现符合预期?
答案1
在 Bash 和 Zsh 中,删除引号后
"\n"
变为换行符\n
,而不是换行符。区别在于echo
内置稍后如何打印它。在 Zsh 中,echo
无论是否-e
解释\n
(和其他序列),都像echo -e
在 Bash 中一样;但在 Bash 中echo
,没有解释则-e
不会。您至少有两种可能性:signature
按照您所做的方式进行定义,并稍后echo -en
解释\n
子字符串。定义
signature
它实际上首先包含换行符。要在此阶段获取换行符,您可以使用ANSI-C 引用:signature=$'get\ndbs\n\nmon, 27 apr 2020 16:11:57 gmt\n\n'
但你需要
echo
不是解释序列,以防您要传递的字符串应包含一个或多个字面上的序列。这个想法是将所有解释放在一个地方。
printf
优于echo
。我会在定义变量时选择 ANSI-C 引用,然后printf
按原样打印。- 在 Bash 中你需要明确双引号变量和命令替换,除非您知道自己在做什么。Zsh 对待双引号或未加引号的变量的方式与 Bash 对待双引号变量的方式相同,因此要复制 Zsh 的行为,您肯定需要在 Bash 中加引号。
以下代码片段在 Bash 和 Zsh 中输出相同的字符串(您称之为“正确的”字符串):
signature=$'get\ndbs\n\nmon, 27 apr 2020 16:11:57 gmt\n\n'
masterKey="t7ejJOwk0HEgkeYCm9v3n8vNwVaW27uriUmTTc3JcBtwqHBfwqO1tAJqKOBpeivurzPl1DxsNFUehEQN5lzGRw=="
hashedSignature="$(printf '%s' "$signature" | openssl dgst -sha256 -mac hmac -macopt hexkey:"$(printf '%s' "$masterKey" | base64 --decode | hexdump -v -e '/1 "%02x"')" -binary | base64)"
echo "Hashed signature: $hashedSignature"