diff --git a/implement-shell-tools/cat/cat.py b/implement-shell-tools/cat/cat.py new file mode 100644 index 00000000..031b6ef4 --- /dev/null +++ b/implement-shell-tools/cat/cat.py @@ -0,0 +1,48 @@ +import argparse +import glob + +def main(): + parser = argparse.ArgumentParser(description="cat with -n and -b options") + parser.add_argument("-n", action="store_true", help="Number all output lines") + parser.add_argument("-b", action="store_true", help="Number non-blank lines (overrides -n)") + parser.add_argument("files", nargs="+", help="Files to read (supports *.txt)") + args = parser.parse_args() + + # -b overrides -n + number_all = args.n + number_nonblank = args.b + if number_all and number_nonblank: + number_all = False + + # Expand wildcard patterns (e.g. *.txt) + file_list = [] + for pattern in args.files: + matched_files = glob.glob(pattern) + if matched_files: + file_list.extend(matched_files) + else: + file_list.append(pattern) + + # Print contents of each file + line_number = 1 + for filename in file_list: + try: + with open(filename, "r") as f: + for line in f: + text = line.rstrip("\n") + if number_nonblank: + if text.strip(): # only number non-blank lines + print(f"{line_number:6}\t{text}") + line_number += 1 + else: + print() + elif number_all: + print(f"{line_number:6}\t{text}") + line_number += 1 + else: + print(text) + except FileNotFoundError: + print(f"cat: {filename}: No such file or directory") + +if __name__ == "__main__": + main() diff --git a/implement-shell-tools/ls/ls.py b/implement-shell-tools/ls/ls.py new file mode 100644 index 00000000..7bc1451f --- /dev/null +++ b/implement-shell-tools/ls/ls.py @@ -0,0 +1,23 @@ +import argparse +import os + +parser = argparse.ArgumentParser(description="Display one file per line from ls directory") + +parser.add_argument("-1", dest="one", action="store_true", help="List one file per line") +parser.add_argument("-a", action="store_true", help="Include hidden files (those starting with .)") +parser.add_argument("path", nargs="?", default=".", help="The directory to list (default: current directory)") + +args = parser.parse_args() + + +files = sorted(os.listdir(args.path)) + + +if not args.a: + files = [f for f in files if not f.startswith(".")] + +if args.one: + for f in files: + print(f) +else: + print(" ".join(files)) diff --git a/implement-shell-tools/wc/wc.py b/implement-shell-tools/wc/wc.py new file mode 100644 index 00000000..224ab13f --- /dev/null +++ b/implement-shell-tools/wc/wc.py @@ -0,0 +1,78 @@ +import argparse +import glob + +def count_file(filename): + line_count = 0 + word_count = 0 + byte_count = 0 + + try: + with open(filename, "rb") as f: + content = f.read() + byte_count = len(content) + text = content.decode("utf-8", errors="replace") + lines = text.splitlines() + line_count = len(lines) + word_count = sum(len(line.split()) for line in lines) + + return (line_count, word_count, byte_count) + except FileNotFoundError: + print(f"wc: {filename}: No such file or directory") + return None + +def main(): + parser = argparse.ArgumentParser(description="Python version of wc") + parser.add_argument("-l", action="store_true", help="Count lines") + parser.add_argument("-w", action="store_true", help="Count words") + parser.add_argument("-c", action="store_true", help="Count bytes") + parser.add_argument("files", nargs="+", help="Files to read (supports wildcards)") + args = parser.parse_args() + + # If no flag is given, show all + show_lines = args.l + show_words = args.w + show_bytes = args.c + if not (show_lines or show_words or show_bytes): + show_lines = show_words = show_bytes = True + + file_list = [] + for pattern in args.files: + matched = glob.glob(pattern) + if matched: + file_list.extend(matched) + else: + file_list.append(pattern) + + total_lines = total_words = total_bytes = 0 + for filename in file_list: + result = count_file(filename) + if result is None: + continue + lines, words, bytes_ = result + total_lines += lines + total_words += words + total_bytes += bytes_ + + output = [] + if show_lines: + output.append(f"{lines:7}") + if show_words: + output.append(f"{words:7}") + if show_bytes: + output.append(f"{bytes_:7}") + output.append(filename) + print(" ".join(output)) + + if len(file_list) > 1: + output = [] + if show_lines: + output.append(f"{total_lines:7}") + if show_words: + output.append(f"{total_words:7}") + if show_bytes: + output.append(f"{total_bytes:7}") + output.append("total") + print(" ".join(output)) + +if __name__ == "__main__": + main()