web-dev-qa-db-ja.com

Linuxbashで文字列からcrc32チェックサムを計算する方法

私は昔、crc32を使って刺し傷からチェックカムを計算しましたが、どうやってそれをしたのか思い出せません。

echo -n "LongString" | crc32    # no output

Pythonで計算するための解決策[1]を見つけましたが、文字列から計算する直接的な方法はありませんか?

# signed
python -c 'import binascii; print binascii.crc32("LongString")'
python -c 'import zlib; print zlib.crc32("LongString")'
# unsigned
python -c 'import binascii; print binascii.crc32("LongString") % (1<<32)'
python -c 'import zlib; print zlib.crc32("LongString") % (1<<32)'

[1] オンラインの結果と一致するようにPythonでCRC32を計算する方法は?

5
oxidworks

私は自分でこの問題に直面し、crc32をインストールするという「面倒」に行きたくありませんでした。私はこれを思いついた、そしてそれは少し厄介ですが、それはほとんどのプラットフォーム、またはとにかくほとんどの最新のLinuxで動作するはずです...

echo -n "LongString" | gzip -c | tail -c8 | hexdump -n4 -e '"%u"'

技術的な詳細を提供するために、 gzipはcrc32を使用 最後の8バイトで、-cオプションを使用すると標準出力に出力され、tailは最後の8バイトを削除します。

hexdumpは少しトリッキーで、満足のいくものを思いつく前にしばらくそれをいじくり回さなければなりませんでしたが、ここでの形式はgzipcrc32を単一の32ビット数として正しく解析しているようです。

  • -n4は、gzipフッターの関連する最初の4バイトのみを取得します。
  • '"%u"'は、バイトを単一の符号なし32ビット整数としてフォーマットする標準のfprintfフォーマット文字列です。 ここでは一重引用符の中に二重引用符がネストされていることに注意してください

16進数のチェックサムが必要な場合は、フォーマット文字列を'"%08x"'(または大文字の16進数の場合は'"%08X"')に変更すると、チェックサムが8文字(0が埋め込まれた)16進数としてフォーマットされます。

私が言うように、最も洗練されたソリューションではなく、おそらくパフォーマンスに敏感なシナリオで使用したいアプローチではなく、使用されるコマンドのほぼ普遍性を考えると魅力的なアプローチです。

クロスプラットフォームの使いやすさの弱点は、おそらくhexdump構成です。これは、プラットフォームごとにバリエーションがあり、少し面倒だからです。これを使用している場合は、いくつかのテスト値を試して、 オンラインツールの結果 と比較することをお勧めします。

[〜#〜] edit [〜#〜]コメントで@PedroGimenoが示唆しているように、出力をodにパイプできます。 hexdumpの代わりに、面倒なオプションなしで同じ結果を得ることができます。 ... | od -t x4 -N 4 -A n(16進数の場合)... | od -t d4 -N 4 -A n(10進数の場合)。

14
robert

または、プロセス置換を使用します。

crc32 <(echo "LongString")
12
C Würtz

少なくともUbuntuでは、/usr/bin/crc32は短いPerlスクリプトであり、そのソースから、ファイルを開くことしかできないことがはっきりとわかります。 stdinから読み取る機能はありません。ファイル名としての-、または-cパラメータなどの特別な処理はありません。

したがって、最も簡単なアプローチは、それを使用して一時ファイルを作成することです。

tmpfile=$(mktemp)
echo -n "LongString" > "$tmpfile"
crc32 "$tmpfile"
rm -f "$tmpfile"

本当にファイルを書きたくない場合(たとえば、ファイルシステムが取ることができるよりも多くのデータがある場合-それが本当に「長い文字列」である可能性は低いですが、議論のために...)、名前付きパイプ。単純な非ランダムアクセスリーダーにとって、これはファイルと見分けがつきません。

fifo=$(mktemp -u)
mkfifo "$fifo"
echo -n "LongString" > "$fifo" &
crc32 "$fifo"
rm -f "$fifo"

&は、次のコマンドが読み取るまでブロックされるため、fifoに書き込むプロセスをバックグラウンドで実行することに注意してください。

一時ファイルの作成についてさらに注意を払うには、以下を参照してください。 https://unix.stackexchange.com/questions/181937/how-create-a-temporary-file-in-Shell-script


または、スクリプトの内容を例として使用して、独自のPerlワンライナーを作成するか(システムにcrc32が存在する場合、Perlと必要なモジュールがインストールされていることを示します)、またはPythonあなたがすでに見つけたワンライナー。

6
slim

あなたの質問にはすでにほとんどの答えがあります。

echo -n 123456789 | python -c 'import sys;import zlib;print(zlib.crc32(sys.stdin.read())%(1<<32))'

正しく3421780262

私は16進数が好きです:

echo -n 123456789 | python -c 'import sys;import zlib;print("%08x"%(zlib.crc32(sys.stdin.read())%(1<<32)))'
cbf43926

CRC-32アルゴリズムがいくつかあることに注意してください。 http://reveng.sourceforge.net/crc-catalogue/all.htm#crc.cat-bits.32

4
Mark Adler

純粋なBashの実装は次のとおりです。

#!/usr/bin/env bash

declare -i -a CRC32_LOOKUP_TABLE

__generate_crc_lookup_table() {
  local -i -r LSB_CRC32_POLY=0xEDB88320 # The CRC32 polynomal LSB order
  local -i index byte lsb
  for index in {0..255}; do
    ((byte = 255 - index))
    for _ in {0..7}; do # 8-bit lsb shift
      ((lsb = byte & 0x01, byte = ((byte >> 1) & 0x7FFFFFFF) ^ (lsb == 0 ? LSB_CRC32_POLY : 0)))
    done
    ((CRC32_LOOKUP_TABLE[index] = byte))
  done
}
__generate_crc_lookup_table
typeset -r CRC32_LOOKUP_TABLE

crc32_string() {
  [[ ${#} -eq 1 ]] || return
  local -i i byte crc=0xFFFFFFFF index
  for ((i = 0; i < ${#1}; i++)); do
    byte=$(printf '%d' "'${1:i:1}") # Get byte value of character at i
    ((index = (crc ^ byte) & 0xFF, crc = (CRC32_LOOKUP_TABLE[index] ^ (crc >> 8)) & 0xFFFFFFFF))
  done
  echo $((crc ^ 0xFFFFFFFF))
}

printf 'The CRC32 of: %s\nis: %08x\n' "${1}" "$(crc32_string "${1}")"

# crc32_string "The quick brown fox jumps over the lazy dog"
# yields 414fa339

テスト:

bash ./crc32.sh "The quick brown fox jumps over the lazy dog"
The CRC32 of: The quick brown fox jumps over the lazy dog
is: 414fa339
3
Léa Gris

cksumを使用し、シェル組み込みのprintfを使用して16進数に変換します。

$ echo -n "LongString"  | cksum | cut -d\  -f1 | xargs echo printf '%0X\\n' | sh
5751BDB2
1
jimis