diff --git a/.gitignore b/.gitignore index 3c3629e6..cc8b5568 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +prep/ diff --git a/implement-shell-tools/cat/cat.py b/implement-shell-tools/cat/cat.py new file mode 100644 index 00000000..108678d9 --- /dev/null +++ b/implement-shell-tools/cat/cat.py @@ -0,0 +1,50 @@ +import sys +import argparse + +# Setup argument parser +parser = argparse.ArgumentParser( + prog="cat", + description="Concatenate and display files" +) + +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 lines only") +parser.add_argument("paths", nargs='+', help="Files to read") + +args = parser.parse_args() + +line_number = 0 # Shared counter across all files + +# Process each file +for path in args.paths: # LEVEL 1: for loop starts + with open(path, "r") as f: # LEVEL 2: inside for loop + content = f.read() # LEVEL 3: inside with block + + # Check if numbering is needed + if args.number: # LEVEL 2: inside for loop + lines = content.split("\n") # LEVEL 3: inside if + numbered_lines = [] + + for index, line in enumerate(lines): # LEVEL 3: inside if + line_number = line_number + 1 # LEVEL 4: inside inner for + numbered_line = f"{line_number:6}\t{line}" + numbered_lines.append(numbered_line) + + print("\n".join(numbered_lines)) # LEVEL 3: inside if + + elif args.number_nonblank: # LEVEL 2: inside for loop + lines = content.split("\n") # LEVEL 3: inside elif + numbered_lines = [] + + for line in lines: # LEVEL 3: inside elif + if line.strip() == "": # LEVEL 4: inside inner for + numbered_lines.append(line) + else: + line_number = line_number + 1 + numbered_line = f"{line_number:6}\t{line}" + numbered_lines.append(numbered_line) + + print("\n".join(numbered_lines)) + + else: # LEVEL 2: inside for loop + print(content) # LEVEL 3: inside else \ 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 00000000..c99aaea3 --- /dev/null +++ b/implement-shell-tools/ls/ls.py @@ -0,0 +1,24 @@ +import os +import argparse + +# Setup argument parser +parser = argparse.ArgumentParser( + prog="ls", + description="Lists contents of a directory" +) + +parser.add_argument("-1", dest="one_column", action="store_true", help="List one file per line") +parser.add_argument("-a", "--all", action="store_true", help="Include hidden files") +parser.add_argument("path", nargs='?', default=".", help="Directory to list (default: current directory)") + +args = parser.parse_args() + +# List directory contents +files = os.listdir(args.path) + +# Filter out hidden files unless -a flag is used +if not args.all: + files = [f for f in files if not f.startswith('.')] + +for file in files: + print(file) \ 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 00000000..f3e00f0a --- /dev/null +++ b/implement-shell-tools/wc/wc.py @@ -0,0 +1,55 @@ +import argparse + +# Setup argument parser +parser = argparse.ArgumentParser( + prog="wc", + description="Count lines, words, and characters" +) +parser.add_argument("paths", nargs='+', help="Files to count") +parser.add_argument("-l", "--lines", action="store_true", help="Count lines only") +parser.add_argument("-w", "--words", action="store_true", help="Count words only") +parser.add_argument("-c", "--chars", action="store_true", help="Count characters only") + +args = parser.parse_args() + +# Track totals +total_lines = 0 +total_words = 0 +total_chars = 0 + +for path in args.paths: + # Read the file + with open(path, "r") as f: + content = f.read() + + # Count lines, words, characters + lines = len(content.rstrip('\n').split('\n')) + words = len(content.split()) + chars = len(content) + + # Add to totals + total_lines += lines + total_words += words + total_chars += chars + + if args.lines: + print(f"{lines:8} {path}") + elif args.words: + print(f"{words:8} {path}") + elif args.chars: + print(f"{chars:8} {path}") + else: + print(f"{lines:8}{words:8}{chars:8} {path}") + + +# Print totals if multiple files +if len(args.paths) > 1: + if args.lines: + print(f"{total_lines:8} total") + elif args.words: + print(f"{total_words:8} total") + elif args.chars: + print(f"{total_chars:8} total") + else: + print(f"{total_lines:8}{total_words:8}{total_chars:8} total") +