zsh
とbash
を使用して以下のスクリプトを実行すると、異なる結果が得られます。興味深いことに、これは入力文字列の\n
改行が原因です。
zsh
を使用すると、正しいの結果が得られます。
rene@MININT-G1P7G69 Desktop % zsh bash_vs_zsh.sh
Hashed signature: AgTW6P8HlAlfOikDPMa/Q92tX2a0GSdDLVeeZE219BQ=
bash
を使用すると、不正解ハッシュが発生します:
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
を期待どおりに動作させるにはどうすればよいですか?
BashおよびZshでは、引用符を削除すると、"\n"
は改行文字ではなく\n
になります。違いは、echo
ビルトインが後でそれを印刷する方法にあります。 Zshでは、-e
の有無にかかわらずecho
はBashの\n
のようにecho -e
(およびその他のシーケンス)を解釈します。しかし、Bashでは-e
なしのecho
はそうではありません。少なくとも2つの可能性があります。
signature
を定義し、後でecho -en
に\n
サブストリングを解釈させます。signature
を定義して、最初から実際に改行が含まれるようにします。この段階で改行を取得するには、 ANSI-C quoting :を使用できます。
signature=$'get\ndbs\n\nmon, 27 apr 2020 16:11:57 gmt\n\n'
ただし、渡す文字列に1つ以上のシーケンスが文字通り含まれている場合に備えて、echo
notにシーケンスを解釈させる必要があります。アイデアは、すべての解釈を1か所にまとめることです。
printf
はecho
よりも優れています。変数を定義するときにANSI-C引用符を選択し、次に文字通り出力するprintf
を選択します。次のスニペットは、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"