zsh 和 bash 对换行符(\n)的处理方式不同 - 如何修复?

zsh 和 bash 对换行符(\n)的处理方式不同 - 如何修复?

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

  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按原样打印。

  2. 在 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"

相关内容