hashvrfy - ハッシュを検証するシェルスクリプト
複数のチェックサムファイルを、まとめて確認するためのシェルスクリプトを公開します。また、アイキャッチ画像を作成するための、Python スクリプトも公開します。
(There is the English(英語) page.)
(最終更新日: 2021年2月21日)
前書き
OSのISOファイルのような、大きなファイルをWebサイトからダウンロードするとき、念の為、提供されている全てのチェックサムファイルで、ハッシュ値を確認するようにしています。しかし、チェックサムファイルを一つずつ操作するのは面倒なため、複数のチェックサムファイルを、まとめて確認するためのシェルスクリプトを書きました。そのファイルを 以下 に公開します。
また、このページの先頭に配置したアイキャッチ画像は、Python スクリプトで作成しています。そのスクリプトも、このページの 後半 で公開します。
ハッシュを検証するシェルスクリプト
ファイル
以下の4つのファイルを作成しました。これらのファイルは、クリエイティブ・コモンズ ゼロ 1.0 ユニバーサル ライセンス (CC0 1.0) の下でライセンスされています。
- hashvrfy (ハッシュを検証するシェルスクリプト)
- hashvrfy-en.md (Pandoc Markdown 形式の英語マニュアル)
- hashvrfy-ja.md (Pandoc Markdown 形式の日本語マニュアル)
- convert-md.sh (上記の Pandoc Markdown ファイルを変換するシェルスクリプト)
また、以下は、上記の Pandoc Markdown ファイルを、シェルスクリプトで変換したファイルです。
- hashvrfy-en.html (HTML 形式の英語マニュアル)
- hashvrfy-ja.html (HTML 形式の日本語マニュアル)
- hashvrfy.1.en (man ページ形式の英語マニュアル)
- hashvrfy.1.ja (man ページ形式の日本語マニュアル)
hashvrfy のソースコード
ユーザーの使い勝手を考慮して、上記の hashvrfy シェルスクリプト ファイルのソースコードを、以下に示します。
#!/bin/sh
# @(#) Shell script to verify the hash. Version 0.1
# This shell script and its associated files are licensed under
# the Creative Commons Zero 1.0 Universal License (CC0 1.0).
# https://creativecommons.org/publicdomain/zero/1.0/
# Get this command name (file name)
cmd_name=$(basename "$0")
# If the first argument is "--", skip it
if [ $# -ge 1 ] && [ "$1" = "--" ] ; then
shift
fi
# Check the number of remaining arguments
if [ $# -lt 2 ] ; then
echo "Usage: ${cmd_name} [--] target_file checksum_file [...]" 1>&2
exit 2
fi
# Get the target file name (pathname)
target_file="$1"
shift
# Check the target file
if [ ! -r "$target_file" ] ; then
echo "Cannot read \"${target_file}\" file" 1>&2
exit 2
fi
# Get the target basename
target_base=$(basename "$target_file")
# Process each checksum file name (pathname)
for checksum_file ; do
# Check the checksum file
if [ ! -r "$checksum_file" ] ; then
echo "Cannot read \"${checksum_file}\" file" 1>&2
exit 2
fi
# Get the checksum basename
checksum_base=$(basename "$checksum_file")
# Make a hint to search a type of hash algorithm
#
# It is made from the checksum basename.
# If it includes the target basename,
# the target basename will be deleted.
#
# Examples:
# Example 1 Example 2
# target_base os.iso os.iso
# checksum_base MD5SUMS os.iso.sha256
# algo_hint MD5SUMS .sha256
#
algo_hint=$(echo "$checksum_base" | sed -e "s/$target_base//")
# Search the hint for the type of hash algorithm
#
# If the type is found, a hash command will be made from it.
# If the type is not found, the hash command will be left empty string.
#
# Examples:
# Example 1 Example 2
# algo_hint MD5SUMS .sha256
# algo_type md5 sha256
# hash_cmd md5sum sha256sum
#
hash_cmd= # Set empty string
for algo_type in md5 sha1 sha224 sha256 sha384 sha512 ; do
if echo "$algo_hint" | grep -q -i "$algo_type" ; then
hash_cmd="${algo_type}sum"
break
fi
done
# Check whether the type of hash algorithm is found or not
if [ -z "$hash_cmd" ] ; then
echo "Cannot decide the hash algorithm of \"${checksum_file}\" file" 1>&2
exit 2
fi
# Check whether the hash command is found or not
if ! type "$hash_cmd" > /dev/null 2>&1 ; then
echo "Cannot find the \"${hash_cmd}\" command" 1>&2
exit 2
fi
# Get a count of the lines including the target pathname
# from the checksum file
#
# Format examples of the checksum file:
#
# Default-style
# 123...def readme.txt (for text file)
# 123...def *os-amd64.iso (for binary file)
#
# BSD-style
# SHA256 (os-amd64.iso) = 123...def
#
target_dot=$(echo "$target_file" | sed -e "s/\./[.]/g")
target_ptrn="[[:blank:]][*]?${target_dot}\$|\\(${target_dot}\\)"
target_cnt=$(grep -E -c "$target_ptrn" "$checksum_file")
# Check the count
#
# Continue processing only if the count is 1.
# Otherwise, it is an error.
#
if [ "$target_cnt" -lt 1 ] ; then
echo \
"Not find the line including \"${target_file}\" string in \"${checksum_file}\" file" \
1>&2
exit 2
elif [ "$target_cnt" -gt 1 ] ; then
echo \
"found the multiple lines including \"${target_file}\" string in \"${checksum_file}\" file" \
1>&2
exit 2
fi
# Extract the line including the target pathname
# from the checksum file
target_line=$(grep -E "$target_ptrn" "$checksum_file")
# Execute the hash command with the line including the target pathname
if echo "$target_line" | $hash_cmd --check --status ; then
echo "${checksum_file}: OK"
else
echo "${checksum_file}: Failed"
exit 1
fi
# Correspond to "for checksum_file ; do" line
done
# Exit successfully
exit 0
例
以下の例では、一行が長くなりすぎるのを防ぐため、バックスラッシュ(\)を使って、複数行で入力しています。しかし、一行で入力しても、問題なく動作します。
Ubuntu
$ ls -1
MD5SUMS
SHA1SUMS
SHA256SUMS
ubuntu-18.04.3-desktop-amd64.iso
$ hashvrfy ubuntu-18.04.3-desktop-amd64.iso \
> MD5SUMS SHA1SUMS SHA256SUMS
MD5SUMS: OK
SHA1SUMS: OK
SHA256SUMS: OK
$
FreeBSD
$ ls -1
CHECKSUM.SHA256-FreeBSD-12.0-RELEASE-amd64
CHECKSUM.SHA512-FreeBSD-12.0-RELEASE-amd64
FreeBSD-12.0-RELEASE-amd64-dvd1.iso
$ hashvrfy FreeBSD-12.0-RELEASE-amd64-dvd1.iso \
> CHECKSUM.SHA256-FreeBSD-12.0-RELEASE-amd64 \
> CHECKSUM.SHA512-FreeBSD-12.0-RELEASE-amd64
CHECKSUM.SHA256-FreeBSD-12.0-RELEASE-amd64: OK
CHECKSUM.SHA512-FreeBSD-12.0-RELEASE-amd64: OK
$
Apache HTTP Server
$ ls -1
httpd-2.4.41.tar.gz
httpd-2.4.41.tar.gz.md5
httpd-2.4.41.tar.gz.sha1
httpd-2.4.41.tar.gz.sha256
$ hashvrfy httpd-2.4.41.tar.gz httpd-2.4.41.tar.gz.md5 \
> httpd-2.4.41.tar.gz.sha1 httpd-2.4.41.tar.gz.sha256
httpd-2.4.41.tar.gz.md5: OK
httpd-2.4.41.tar.gz.sha1: OK
httpd-2.4.41.tar.gz.sha256: OK
$
アイキャッチ画像を作成するための Python スクリプト
このページの先頭に配置したアイキャッチ画像 (featured image) は、以下に示す、Python スクリプトを元に作成しています。
#!/usr/bin/env python3
# Python script to make the featured-image (SVG format).
# This script is tested with Python 3.6.9, svgwrite 1.4 and noise 1.2.2
# on Ubuntu 18.04.
# Public Sans 1.008 is licensed under the SIL Open Font License 1.1
# https://public-sans.digital.gov/
import math
import svgwrite
import noise
# Attribute values of image
image_size = (image_width, image_height) = (960, 600) # 16:10
# Drawing object of svgwrite
dwg = svgwrite.Drawing(filename='feature-using-font.svg', \
size=image_size, profile='full')
# Background rectangle of image
dwg.add(dwg.rect(insert=(0, 0), size=image_size, fill='white'))
# Attribute value of lines
line_interval = 12
# Vertical lines
vlines = dwg.add(dwg.g(stroke=svgwrite.rgb(51, 51, 51)))
for line_x in range(0, (image_width +1), line_interval):
noise_input = line_x/(line_interval *7)
noise_value = noise.pnoise1(noise_input, base=9)
sin_input = (line_x/(line_interval *20)) * (2*math.pi)
sin_value = math.sin(sin_input + noise_value)
line_width = round(((4.0 * sin_value) +4.5), 4)
vlines.add(dwg.line(start=(line_x, 0), end=(line_x, image_height), \
stroke_width=line_width))
# Horizontal lines
hlines = dwg.add(dwg.g(stroke=svgwrite.rgb(50, 50, 255)))
for line_y in range(0, (image_height +1), line_interval):
noise_input = line_y/(line_interval *7)
noise_value = noise.pnoise1(noise_input, base=17)
sin_input = (line_y/(line_interval *16)) * (2*math.pi)
sin_value = math.sin(sin_input + noise_value)
line_width = round(((3.0 * sin_value) +3.5), 4)
hlines.add(dwg.line(start=(0, line_y), end=(image_width, line_y), \
stroke_width=line_width))
# Background rectangle of text
dwg.add(dwg.rect(insert=(220, 180), size=(520, 240), fill='white'))
# Text 'hashvrfy'
dwg.add(dwg.text('hashvrfy', fill='black', \
text_anchor='middle', insert=((image_width /2), 300), \
font_family='Public Sans', font_weight='bold', font_size=108))
# Text 'shell script'
dwg.add(dwg.text('shell script', fill='black', \
text_anchor='middle', insert=((image_width /2), 386), \
font_family='Public Sans', font_weight='bold', font_size=46))
# Save to the SVG file
dwg.save()
このスクリプトでは、以下の、2つの外部 Python パッケージを使用しています。
アイキャッチ画像の中の幾何学模様は、線 (SVG line) だけで構成されています。全ての線の間隔は、等しくなっています。線の幅は、正弦関数 (サイン関数、sin) を元に、規則的に変化させています。その計算過程で、パーリンノイズの値を加えて、線の幅を、多少、ランダムに変化させています。
この Python スクリプトを実行すると、以下に示す、SVG ファイルが作成されます。
この SVG ファイルでは、Public Sans フォントを使用しています。このフォントがインストールされていない環境で、この SVG ファイルを表示すると、上記の Python スクリプトで意図したように、フォントが表示されません。
そこで、Inkscape を使って、フォントをアウトライン化した SVG ファイルを、以下に示します。このファイルであれば、Public Sans フォントがインストールされていない環境でも、フォント部分が意図した通りに表示されます。
また、同様に、Inkscape を使って、PNG 形式に変換したファイルが、このページの先頭に配置した画像です。
コメント
コメントを投稿