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
48 changes: 48 additions & 0 deletions implement-shell-tools/cat/cat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
import sys
import glob

def cat(files, number_all=False, number_nonblank=False):
line_num = 1
for filename in files:
try:
with open(filename, "r") as f:
for line in f:
stripped = line.rstrip("\n")

if number_all:
print(f"{line_num:6}\t{stripped}")
line_num += 1
elif number_nonblank:
if stripped:
print(f"{line_num:6}\t{stripped}")
line_num += 1
else:
print()
else:
print(stripped)
except FileNotFoundError:
print(f"cat: {filename}: No such file or directory", file=sys.stderr)

def main():
args = sys.argv[1:]

number_all = "-n" in args
number_nonblank = "-b" in args

# Remove flags from args
files = [arg for arg in args if arg not in ("-n", "-b")]

# Expand globs like *.txt
expanded_files = []
for file in files:
expanded_files.extend(glob.glob(file))

if not expanded_files:
print("cat: missing file operand", file=sys.stderr)
sys.exit(1)

cat(expanded_files, number_all=number_all, number_nonblank=number_nonblank)

if __name__ == "__main__":
main()
49 changes: 49 additions & 0 deletions implement-shell-tools/ls/ls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
import sys
import os

def list_dir(path=".", show_all=False):
try:
entries = os.listdir(path)
if not show_all:
entries = [e for e in entries if not e.startswith(".")]
return sorted(entries)
except FileNotFoundError:
print(f"ls: cannot access '{path}': No such file or directory", file=sys.stderr)
return []
except NotADirectoryError:
# If it's a file, just return it
return [path]

def main():
args = sys.argv[1:]

# Flags
show_one_per_line = "-1" in args
show_all = "-a" in args

# Remove flags from args
paths = [arg for arg in args if arg not in ("-1", "-a")]

if not paths:
paths = ["."] # default to current directory

for i, path in enumerate(paths):
entries = list_dir(path, show_all=show_all)

if len(paths) > 1:
print(f"{path}:")

for entry in entries:
if show_one_per_line:
print(entry)
else:
print(entry, end=" ")
if not show_one_per_line:
print() # newline after the row

if i < len(paths) - 1:
print()

if __name__ == "__main__":
main()
81 changes: 81 additions & 0 deletions implement-shell-tools/wc/wc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env python3
import sys
import glob
import os

def count_file(filename, count_lines, count_words, count_bytes):
try:
with open(filename, "rb") as f: # open in binary to count bytes correctly
data = f.read()
except FileNotFoundError:
print(f"wc: {filename}: No such file or directory", file=sys.stderr)
return None

text = data.decode(errors="ignore")
lines = text.splitlines()

l = len(lines)
w = len(text.split())
c = len(data)

results = []
if count_lines:
results.append(str(l))
if count_words:
results.append(str(w))
if count_bytes:
results.append(str(c))

if not (count_lines or count_words or count_bytes):
# default: all three
results = [str(l), str(w), str(c)]

return results, filename, (l, w, c)

def main():
args = sys.argv[1:]

count_lines = "-l" in args
count_words = "-w" in args
count_bytes = "-c" in args

# remove flags from args
files = [arg for arg in args if arg not in ("-l", "-w", "-c")]

if not files:
print("wc: missing file operand", file=sys.stderr)
sys.exit(1)

expanded_files = []
for f in files:
expanded_files.extend(glob.glob(f))

if not expanded_files:
print("wc: no matching files", file=sys.stderr)
sys.exit(1)

total_l, total_w, total_c = 0, 0, 0

for filename in expanded_files:
result = count_file(filename, count_lines, count_words, count_bytes)
if result:
res, name, (l, w, c) = result
print(f"{' '.join(res)} {name}")
total_l += l
total_w += w
total_c += c

if len(expanded_files) > 1:
total_results = []
if count_lines:
total_results.append(str(total_l))
if count_words:
total_results.append(str(total_w))
if count_bytes:
total_results.append(str(total_c))
if not (count_lines or count_words or count_bytes):
total_results = [str(total_l), str(total_w), str(total_c)]
print(f"{' '.join(total_results)} total")

if __name__ == "__main__":
main()