Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules
prep/
37 changes: 37 additions & 0 deletions implement-shell-tools/cat/cat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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 = 1 # Shared counter across all files

for path in args.paths:
with open(path, "r") as f:

lines = f.read().splitlines()

output = []
for line in lines:
if args.number_nonblank:
if line.strip():
output.append(f"{line_number:6}\t{line}")
line_number += 1
else:
output.append(line)
elif args.number:
output.append(f"{line_number:6}\t{line}")
line_number += 1
else:
output.append(line)

print("\n".join(output))
30 changes: 30 additions & 0 deletions implement-shell-tools/ls/ls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import os
import argparse

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("paths", nargs='*', default=["."], help="Directories to list")

args = parser.parse_args()

for path in args.paths:
if len(args.paths) > 1:
print(f"{path}:")

try:
files = os.listdir(path)
if not args.all:
files = [f for f in files if not f.startswith('.')]

files.sort()

sep = "\n" if args.one_column else " "
print(sep.join(files))

if len(args.paths) > 1:
print()

except FileNotFoundError:
print(f"ls: cannot access '{path}': No such file or directory")
42 changes: 42 additions & 0 deletions implement-shell-tools/wc/wc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import argparse

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")
parser.add_argument("-w", "--words", action="store_true")
parser.add_argument("-c", "--chars", action="store_true")

args = parser.parse_args()

# If no flags are provided, the default behavior is to show all three
show_all = not (args.lines or args.words or args.chars)

total_stats = [0, 0, 0] # lines, words, chars

for path in args.paths:
with open(path, "r") as f:
content = f.read()

stats = [
len(content.splitlines()),
len(content.split()),
len(content)
]

for i in range(3):
total_stats[i] += stats[i]

output = []
if args.lines or show_all: output.append(f"{stats[0]:8}")
if args.words or show_all: output.append(f"{stats[1]:8}")
if args.chars or show_all: output.append(f"{stats[2]:8}")

print(f"{''.join(output)} {path}")

if len(args.paths) > 1:
total_output = []
if args.lines or show_all: total_output.append(f"{total_stats[0]:8}")
if args.words or show_all: total_output.append(f"{total_stats[1]:8}")
if args.chars or show_all: total_output.append(f"{total_stats[2]:8}")

print(f"{''.join(total_output)} total")