Skip to content

Commit e0906b9

Browse files
committed
python implementation of wc
1 parent 0d6e0cf commit e0906b9

File tree

1 file changed

+82
-0
lines changed
  • implement-shell-tools/wc

1 file changed

+82
-0
lines changed

implement-shell-tools/wc/wc.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import argparse
2+
import sys
3+
import glob # to find file paths and match patterns
4+
5+
def parseargs():
6+
parser = argparse.ArgumentParser(
7+
prog = "wc",
8+
description = "wc clone supporting -l, -w, -c flags"
9+
)
10+
parser.add_argument("-l", "--lines", action = "store_true",help = "print line counts")
11+
parser.add_argument("-w", "--words", action ="store_true",help = "print word count")
12+
parser.add_argument("-c", "--bytes", action ="store_true", help = "print byte count")
13+
parser.add_argument("files", nargs="+", help="Files to read (shell globs allowed)")
14+
15+
return parser.parse_args()
16+
17+
#Uses glob to expand patterns like *.txt.
18+
def expand_files(patterns):
19+
expanded = []
20+
for p in patterns:
21+
matches = glob.glob(p)
22+
if matches:
23+
expanded.extend(sorted(matches)) # predictable order
24+
else:
25+
print(f"wc: {p}: No such file", file=sys.stderr) #Prints an error if a pattern matches nothing.
26+
return expanded
27+
28+
def file_counts(filename):
29+
try:
30+
with open(filename, "rb") as f: #opening file in binary mode to be able to count bytes.
31+
data = f.read()
32+
except FileNotFoundError:
33+
print(f"wc: {filename}: No such file", file=sys.stderr)
34+
return None
35+
36+
text = data.decode("utf-8", errors="ignore")
37+
line_count = text.count("\n")
38+
word_count = len(text.split())
39+
byte_count = len(data)
40+
41+
return line_count, word_count, byte_count
42+
43+
def print_counts(filename, counts, show_lines, show_words, show_bytes): #args.lines is passed into the parameter show_lines and same for other arguments.
44+
line_count, word_count, byte_count = counts
45+
46+
# If no flags are set, show all three
47+
if not (show_lines or show_words or show_bytes):
48+
print(f"{line_count:7} {word_count:7} {byte_count:7} {filename}")
49+
return
50+
51+
output = []
52+
if show_lines:
53+
output.append(f"{line_count:7}") #:7 to ensure nums are rightaligned in a spaced column -just like GNU wc
54+
if show_words:
55+
output.append(f"{word_count:7}")
56+
if show_bytes:
57+
output.append(f"{byte_count:7}")
58+
output.append(filename)
59+
print(" ".join(output))
60+
61+
def main():
62+
args = parseargs()
63+
files = expand_files(args.files)
64+
65+
total_lines, total_words, total_bytes = 0, 0, 0
66+
67+
for file in files:
68+
counts = file_counts(file)
69+
if counts is None:
70+
continue
71+
print_counts(file, counts, args.lines, args.words, args.bytes)
72+
total_lines += counts[0]
73+
total_words += counts[1]
74+
total_bytes += counts[2]
75+
76+
# If multiple files, print totals
77+
if len(files) > 1:
78+
total_counts = (total_lines, total_words, total_bytes)
79+
print_counts("total", total_counts, args.lines, args.words, args.bytes)
80+
81+
if __name__ == "__main__":
82+
main()

0 commit comments

Comments
 (0)