-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathmd5.py
More file actions
executable file
·178 lines (162 loc) · 7.07 KB
/
md5.py
File metadata and controls
executable file
·178 lines (162 loc) · 7.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env python
########################################################################
# md5.py: MD5 Checksum Calculator
#
# Description:
# This script calculates MD5 checksums for files and strings. It can process
# individual files, directories, and input strings, and supports various output
# formats including a quiet mode that only displays checksums.
#
# Author: id774 (More info: http://id774.net)
# Source Code: https://github.com/id774/scripts
# License: The GPL version 3, or LGPL version 3 (Dual License).
# Contact: idnanashi@gmail.com
#
# Usage:
# Calculate checksum for files:
# python md5.py [options] file
#
# Calculate checksum for a string:
# python md5.py -s "string"
#
# Options:
# -d, --subdirectory: Include subdirectories when calculating checksums for files.
# -r, --reversed: Reverse the format of the output (checksum first, then file path).
# -q, --quiet: Quiet mode, only the checksum is printed.
# -p, --print: Echo stdin to stdout and append the checksum to stdout (useful for piping).
# -s, --string: Calculate and print the checksum of the given string.
#
# Example:
# Calculate checksum for all files in a directory (including subdirectories):
# python md5.py -d /path/to/directory
#
# Calculate checksum for a single file in quiet mode:
# python md5.py -q /path/to/file
#
# Calculate and print checksum for stdin input:
# echo "sample text" | python md5.py -p
#
# Requirements:
# - Python Version: 3.3 or later
#
# Version History:
# v1.3 2025-07-01
# Standardized termination behavior for consistent script execution.
# v1.2 2025-06-23
# Unified usage output to display full script header and support common help/version options.
# v1.1 2025-04-14
# Unify error and info message formatting with stderr and prefix tags.
# v1.0 2023-06-24
# Initial release. Functionality for calculating MD5 checksums of files and
# strings, supporting subdirectories, reverse output format, and quiet mode.
#
########################################################################
import hashlib
import os
import sys
from optparse import OptionParser
from stat import S_ISDIR, ST_MODE
def usage():
""" Display the script header as usage information and exit. """
script_path = os.path.abspath(__file__)
in_header = False
try:
with open(script_path, 'r', encoding='utf-8') as f:
for line in f:
if line.strip().startswith('#' * 10):
if not in_header:
in_header = True
continue
else:
break
if in_header and line.startswith('#'):
if line.startswith('# '):
print(line[2:], end='')
else:
print(line[1:], end='')
except Exception as e:
print("Error reading usage information: %s" % str(e), file=sys.stderr)
sys.exit(1)
sys.exit(0)
class Md5Checksum:
@staticmethod
def calculate_checksum(path):
""" Calculate and return the MD5 checksum for a given file. """
m = hashlib.md5()
with open(path, 'rb') as f:
for line in f:
m.update(line)
return m.hexdigest()
@staticmethod
def calculate_checksum_for_string(input_string):
""" Calculate and return the MD5 checksum for a given input string. """
m = hashlib.md5()
m.update(input_string.encode('utf-8'))
return m.hexdigest()
def print_checksum(include_subdir, reversed_format, quiet_mode, paths):
""" Calculate and print MD5 checksums for given paths with optional inclusion of subdirectories. """
script_name = os.path.basename(sys.argv[0])
for path in paths:
if not os.path.exists(path):
print("[WARN] {0}: {1}: No such file or directory".format(script_name, path), file=sys.stderr)
continue
if include_subdir and S_ISDIR(os.stat(path)[ST_MODE]):
for root, dirs, files in os.walk(path):
for file in files:
full_path = os.path.join(root, file)
checksum = Md5Checksum.calculate_checksum(full_path)
print_formatted_checksum(
checksum, full_path, reversed_format, quiet_mode, is_file=True)
elif S_ISDIR(os.stat(path)[ST_MODE]):
print("[WARN] {0}: {1}: Is a directory".format(script_name, path), file=sys.stderr)
else:
checksum = Md5Checksum.calculate_checksum(path)
print_formatted_checksum(
checksum, path, reversed_format, quiet_mode, is_file=True)
def print_formatted_checksum(checksum, path, reversed_format, quiet_mode, is_file):
""" Print the MD5 checksum in a formatted manner based on the provided options. """
if quiet_mode:
print(checksum)
elif reversed_format:
print("{0} {1}".format(checksum, path if is_file else '"{}"'.format(path)))
else:
print("MD5 ({0}) = {1}".format(
path if is_file else '"{}"'.format(path), checksum))
def main():
""" Parse command-line arguments and execute the MD5 checksum calculation and printing. """
usage = "usage: %prog [options] file"
parser = OptionParser(usage)
parser.add_option("-v", "--version", help="show the version and exit",
action="store_true", dest="version")
parser.add_option("-d", "--subdirectory", help="include sub directory",
action="store_true", dest="include_subdir")
parser.add_option("-r", "--reversed", help="reverses the format of the output",
action="store_true", dest="reversed_format")
parser.add_option("-q", "--quiet", help="quiet mode - only the checksum is printed out",
action="store_true", dest="quiet_mode")
parser.add_option("-p", "--print", help="echo stdin to stdout and append the checksum to stdout",
action="store_true", dest="print_stdin")
parser.add_option("-s", "--string", help="print a checksum of the given string",
action="store", type="string", dest="input_string")
(options, args) = parser.parse_args()
if options.input_string:
checksum = Md5Checksum.calculate_checksum_for_string(
options.input_string)
print_formatted_checksum(checksum, options.input_string,
options.reversed_format, options.quiet_mode, is_file=False)
elif options.print_stdin:
input_data = sys.stdin.read()
print(input_data, end='')
checksum = Md5Checksum.calculate_checksum_for_string(input_data)
print("{0}".format(checksum))
else:
print_checksum(options.include_subdir,
options.reversed_format, options.quiet_mode, args)
return 0
if __name__ == '__main__':
if len(sys.argv) < 2 or sys.argv[1] in ('-h', '--help', '-v', '--version'):
usage()
if sys.version_info < (3, 3):
print("[ERROR] This script requires Python 3.3 or later.", file=sys.stderr)
sys.exit(9)
sys.exit(main())