diff --git a/implement-shell-tools/cat/cat.py b/implement-shell-tools/cat/cat.py new file mode 100644 index 000000000..8d350ea73 --- /dev/null +++ b/implement-shell-tools/cat/cat.py @@ -0,0 +1,30 @@ +import argparse +import sys + +parser = argparse.ArgumentParser( + prog="cat", + description="Concatenate files and print on the standard output", +) +parser.add_argument("-n", "--number", action="store_true", + help="Number all output lines") +parser.add_argument("-b", "--number-nonblank", action="store_true", + help="Number non-empty output lines, overrides -n") +parser.add_argument("files", nargs="+", help="The files to print") + +args = parser.parse_args() + +counter = 0 +for path in args.files: + with open(path, "r") as f: + for line in f: + if args.number_nonblank: + if line.strip("\n") == "": + sys.stdout.write(line) + else: + counter += 1 + sys.stdout.write(f"{counter:6}\t{line}") + elif args.number: + counter += 1 + sys.stdout.write(f"{counter:6}\t{line}") + else: + sys.stdout.write(line) \ No newline at end of file diff --git a/implement-shell-tools/ls/ls.py b/implement-shell-tools/ls/ls.py new file mode 100644 index 000000000..cd164e369 --- /dev/null +++ b/implement-shell-tools/ls/ls.py @@ -0,0 +1,53 @@ +import argparse +import os +import sys + +parser = argparse.ArgumentParser(prog="ls", description="List directory contents") +parser.add_argument("-1", dest="one_per_line", action="store_true", + help="List one file per line") +parser.add_argument("-a", "--all", action="store_true", + help="Do not ignore entries starting with .") +parser.add_argument("paths", nargs="*", default=["."], + help="The files or directories to list") + +args = parser.parse_args() + + +def entries(directory): + names = os.listdir(directory) + if args.all: + names = names + [".", ".."] + else: + names = [name for name in names if not name.startswith(".")] + return sorted(names, key=lambda name: name.lstrip(".").lower()) + + +files = [] +directories = [] +for path in args.paths: + if os.path.isdir(path): + directories.append(path) + elif os.path.exists(path): + files.append(path) + else: + print(f"ls: cannot access '{path}': No such file or directory", + file=sys.stderr) + +files.sort() +directories.sort() + +show_headers = len(args.paths) > 1 +printed_anything = False + +for path in files: + print(path) + printed_anything = True + +for directory in directories: + if show_headers: + if printed_anything: + print() + print(f"{directory}:") + for name in entries(directory): + print(name) + printed_anything = True \ No newline at end of file diff --git a/implement-shell-tools/wc/wc.py b/implement-shell-tools/wc/wc.py new file mode 100644 index 000000000..dad094d44 --- /dev/null +++ b/implement-shell-tools/wc/wc.py @@ -0,0 +1,48 @@ +import argparse +import os + +parser = argparse.ArgumentParser(prog="wc", description="Print newline, word and byte counts") +parser.add_argument("-l", "--lines", action="store_true", help="Print the newline counts") +parser.add_argument("-w", "--words", action="store_true", help="Print the word counts") +parser.add_argument("-c", "--bytes", action="store_true", help="Print the byte counts") +parser.add_argument("files", nargs="+", help="The files to count") + +args = parser.parse_args() + +show_all = not (args.lines or args.words or args.bytes) +show_lines = args.lines or show_all +show_words = args.words or show_all +show_bytes = args.bytes or show_all + +rows = [] +total = [0, 0, 0] + +for path in args.files: + with open(path, "rb") as f: + data = f.read() + counts = [data.count(b"\n"), len(data.split()), len(data)] + for i in range(3): + total[i] += counts[i] + rows.append((counts, path)) + +if len(args.files) > 1: + rows.append((total, "total")) + width = len(str(sum(os.path.getsize(path) for path in args.files))) +else: + width = 1 + + +def selected(counts): + chosen = [] + if show_lines: + chosen.append(counts[0]) + if show_words: + chosen.append(counts[1]) + if show_bytes: + chosen.append(counts[2]) + return chosen + + +for counts, label in rows: + columns = " ".join(f"{value:{width}}" for value in selected(counts)) + print(f"{columns} {label}") \ No newline at end of file