Bashで8バイトを符号なし整数(64ビットLE)に変換するには?

Bashで8バイトを符号なし整数(64ビットLE)に変換するには?

8バイトをどのように「読み取り/解釈」するのですか?署名されていない整数(リトルエンディアン)
たぶんこれを達成するためのBash-fuの魔法の変換はありますか?

更新:
私の質問の説明に何かが交差しているようです。以下は、私がやろうとしている作業のより広範な例です。

ファイルの最初(および最後)64kを読みたいです。各8バイトの単語は、64ビットのLittle-Endian符号なし整数として解釈されます。これら整数ファイルを一意に識別するために使用されるハッシュ計算。したがって、多くの計算が必要であるため、∴速度が好ましいが、重要ではない。 (私がこれを行う理由は何ですか?smplayer再生されるメディアの.iniファイルの名前をハッシュし、そのファイルにアクセスして変更しようとしているので、BashでsmplayerのC ++コードを模倣します。)

パイプ入力を受け入れるのに適した解決策が最適であり、Bash変数が\ x00.を処理できないため、これは不可欠です。

私はこのようなものがPython、Perl、C / C ++などの言語に適している可能性があることを知っていますが、PythonとPerlを知らず、C ++でこれを行うことはできますが、実際には使用しませんでした。長年、私はFocus on Bashを試してきました。

短いPerlとPythonのスニペットをお勧めします。 Bashが優先されます(ただし速度が低下するわけではありません)。

ベストアンサー1

Bashは単に間違ったツールです。シェルはピースを互いに貼り付けるのに堪能です。テキスト処理と算術は側面で提供されますが、データ処理は単にその権限に属しません。

Pythonにはすぐに大きな数字があるので、Perlの代わりにPythonを選択します。使用struct.unpackデータを解凍します。

#!/usr/bin/env python
import os, struct, sys
fmt = "<" + "Q" * 8192
header_bytes = sys.stdin.read(65536)
header_ints = list(struct.unpack(fmt, header_bytes))
sys.stdin.seek(-65536, 2)
footer_bytes = sys.stdin.read(65536)
footer_ints = list(struct.unpack(fmt, header_bytes))
# your calculations here

これが元の質問に対する私の答えです。修正された問題は、8バイトシーケンスをリトルエンディアンシーケンスの64ビット整数表現に変換する元の問題とはほとんど関係がありません。

私はbashに組み込まれた機能がないと思います。次のコードスニペットは、a指定された文字列のバイトに対応する数値の16進表現である文字列を設定します。ビッグエンディアン方式注文する。

a=0x$(printf "%s" "$string" |
      od -t x1 -An |
      tr -dc '[:alnum:]')

リトルエンディアン順序の場合は、元の文字列のバイト順序を逆に置き換えます。 Bashでは、既知の長さの文字列に対して次のことができます。

a=0x$(printf "%s" "${string:7:1}${string:6:1}${string:5:1}${string:4:1}${string:3:1}${string:2:1}${string:1:1}${string:0:1}" |
      od -t x1 -An |
      tr -dc '[:alnum:]')

od8バイトタイプをサポートしている場合は、プラットフォームで好みのエンディアンを入手することもできます。

a=0x$(printf "%s" "$string" |
      od -t x8 -An |
      tr -dc '[:alnum:]')

算術を実行する能力は、$abashが8バイトの算術をサポートしているかどうかによって異なります。それでも、それを符号付き値として扱います。

またはPerlを使用して:

a=0x$(perl -e 'print unpack "Q<", $ARGV[0]' "$string")

Perlが64ビット整数サポートなしでコンパイルされている場合は、バイトを分割する必要があります。

a=0x$(perl -e 'printf "%x%08x\n", reverse unpack "L<L<", $ARGV[0]' "$string")

(ビッグエンディアン<に交換するか、プラットフォームエンディアンのために削除してください。)>

おすすめ記事