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,2 +1,3 @@
node_modules
.venv
testoutput.txt
54 changes: 54 additions & 0 deletions implement-shell-tools/cat/cat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import sys
import argparse

# 1. Set up argparse to handle flags and files
parser = argparse.ArgumentParser(description="A simple Python implementation of the cat command.")

# Add the optional flags (-n and -b)
parser.add_argument("-n", action="store_true", help="Number all output lines")
parser.add_argument("-b", action="store_true", help="Number nonempty output lines, overrides -n")

# Add the files argument (nargs="*" means it accepts 0 or more files)
parser.add_argument("files", nargs="*", help="Files to read")

# Parse the arguments
args = parser.parse_args()

show_all_numbers = args.n
show_non_blank_numbers = args.b
files = args.files


if not files:
print("Usage: python3 cat.py [-n] [-b] <filenames>")
sys.exit()

line_count = 1
# 3. Process each file
for filename in files:
try:
with open(filename, "r") as file:
for line in file:
# Logic for -b
if show_non_blank_numbers:
if line.strip(): # If line is not empty
print(f"{line_count:>6}\t{line}", end="")
line_count += 1
else:
# Standard cat no flags
print(line, end="")

# Logic for -n
elif show_all_numbers:
print(f"{line_count:>6}\t{line}", end="")
line_count += 1

# Standard cat no flags
else:
print(line, end="")

# throw clear errors
except FileNotFoundError:
print(f"Error: {filename}: No such file or directory")
except IsADirectoryError:
print(f"Error: {filename}: Is a directory")
55 changes: 55 additions & 0 deletions implement-shell-tools/ls/ls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import os
import sys
import argparse

# 1. Set up argparse to handle the ls flags
parser = argparse.ArgumentParser(description="A simple Python implementation of the ls command.")

# Add the -a and -1 flags
parser.add_argument("-a", action="store_true", help="Do not ignore entries starting with .")
parser.add_argument("-1", action="store_true",dest="one_column", help="List one file per line")

# Add the path argument (nargs="?" means it's optional, default is current directory ".")
parser.add_argument("path", nargs="?", default=".", help="Directory path to list")

# Parse the arguments
args = parser.parse_args()

# 2. rename back variables
show_all = args.a
one_column = args.one_column
path = args.path

try:
# Get directory contents
entries = os.listdir(path)

# Handle the -a flag
if show_all:
entries.extend([".", ".."])

# 5. Sort alphabetically
entries.sort()

# Printing Logic
for entry in entries:
# Skip hidden files unless -a is passed
if not show_all and entry.startswith("."):
continue

if one_column:
# -1 flag: Print vertically
print(entry)
else:
# Standard: Print horizontally with spaces
print(entry, end=" ")

# newline only if we not print horizontally
if not one_column:
print()

except FileNotFoundError:
print(f"ls: cannot access '{path}': No such file or directory")
except NotADirectoryError:
# if a file ls just prints the filename
print(path)
68 changes: 68 additions & 0 deletions implement-shell-tools/wc/wc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import sys
import os
import argparse

# 1. Set up argparse to handle the wc flags
parser = argparse.ArgumentParser(description="A simple Python implementation of the wc command.")

# Add the optional flags (-l, -w, -c)
parser.add_argument("-l", action="store_true", help="Print the newline counts")
parser.add_argument("-w", action="store_true", help="Print the word counts")
parser.add_argument("-c", action="store_true", help="Print the byte counts")

# Add the files argument (nargs="*" means it accepts 0 or more files)
parser.add_argument("files", nargs="*", help="Files to process")

# Parse the arguments
args = parser.parse_args()

# 2. Rename back the variables
show_lines = args.l
show_words = args.w
show_chars = args.c
files = args.files

# If no flags then show all.
show_all = not (show_lines or show_words or show_chars)


# Total counters
total_l, total_w, total_c = 0, 0, 0

for filename in files:
try:
with open(filename, 'r') as f:
lines = f.readlines()

# files calculation
l_count = len(lines)
w_count = sum(len(line.split()) for line in lines)
# os.path.getsize for bytes, in .js I used const bytes = Buffer.byteLength(content);
c_count = os.path.getsize(filename)

# Update totals
total_l += l_count
total_w += w_count
total_c += c_count

# Printing Logic
output = []
if show_lines or show_all: output.append(f"{l_count:>8}")
if show_words or show_all: output.append(f"{w_count:>8}")
if show_chars or show_all: output.append(f"{c_count:>8}")

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

except FileNotFoundError:
print(f"wc: {filename}: No such file or directory")
except IsADirectoryError:
print(f"wc: {filename}: Is a directory")
print(f"{'0':>8} {'0':>8} {'0':>8} {filename}")

# Print Total if there were multiple files
if len(files) > 1:
output_total = []
if show_lines or show_all: output_total.append(f"{total_l:>8}")
if show_words or show_all: output_total.append(f"{total_w:>8}")
if show_chars or show_all: output_total.append(f"{total_c:>8}")
print(f"{''.join(output_total)} total")
Loading