web-dev-qa-db-ja.com

改行(\ n)はzshとbashで異なる方法で処理されます-修正方法は?

zshbashを使用して以下のスクリプトを実行すると、異なる結果が得られます。興味深いことに、これは入力文字列の\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を期待どおりに動作させるにはどうすればよいですか?

2
Krumelur
  1. 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つ以上のシーケンスが文字通り含まれている場合に備えて、echonotにシーケンスを解釈させる必要があります。アイデアは、すべての解釈を1か所にまとめることです。

    一般的に printfecho よりも優れています。変数を定義するときに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"
1