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

parser = argparse.ArgumentParser(
prog="cat",
description="Concatenate files and print on the standard output",
)
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 output lines, overrides -n")
parser.add_argument("files", nargs="+", help="The files to print")

args = parser.parse_args()

counter = 0
for path in args.files:
with open(path, "r") as f:
for line in f:
if args.number_nonblank:
if line.strip("\n") == "":
sys.stdout.write(line)
else:
counter += 1
sys.stdout.write(f"{counter:6}\t{line}")
elif args.number:
counter += 1
sys.stdout.write(f"{counter:6}\t{line}")
else:
sys.stdout.write(line)
53 changes: 53 additions & 0 deletions implement-shell-tools/ls/ls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import argparse
import os
import sys

parser = argparse.ArgumentParser(prog="ls", description="List directory contents")
parser.add_argument("-1", dest="one_per_line", action="store_true",
help="List one file per line")
parser.add_argument("-a", "--all", action="store_true",
help="Do not ignore entries starting with .")
parser.add_argument("paths", nargs="*", default=["."],
help="The files or directories to list")

args = parser.parse_args()


def entries(directory):
names = os.listdir(directory)
if args.all:
names = names + [".", ".."]
else:
names = [name for name in names if not name.startswith(".")]
return sorted(names, key=lambda name: name.lstrip(".").lower())


files = []
directories = []
for path in args.paths:
if os.path.isdir(path):
directories.append(path)
elif os.path.exists(path):
files.append(path)
else:
print(f"ls: cannot access '{path}': No such file or directory",
file=sys.stderr)

files.sort()
directories.sort()

show_headers = len(args.paths) > 1
printed_anything = False

for path in files:
print(path)
printed_anything = True

for directory in directories:
if show_headers:
if printed_anything:
print()
print(f"{directory}:")
for name in entries(directory):
print(name)
printed_anything = True
48 changes: 48 additions & 0 deletions implement-shell-tools/wc/wc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import argparse
import os

parser = argparse.ArgumentParser(prog="wc", description="Print newline, word and byte counts")
parser.add_argument("-l", "--lines", action="store_true", help="Print the newline counts")
parser.add_argument("-w", "--words", action="store_true", help="Print the word counts")
parser.add_argument("-c", "--bytes", action="store_true", help="Print the byte counts")
parser.add_argument("files", nargs="+", help="The files to count")

args = parser.parse_args()

show_all = not (args.lines or args.words or args.bytes)
show_lines = args.lines or show_all
show_words = args.words or show_all
show_bytes = args.bytes or show_all

rows = []
total = [0, 0, 0]

for path in args.files:
with open(path, "rb") as f:
data = f.read()
counts = [data.count(b"\n"), len(data.split()), len(data)]
for i in range(3):
total[i] += counts[i]
rows.append((counts, path))

if len(args.files) > 1:
rows.append((total, "total"))
width = len(str(sum(os.path.getsize(path) for path in args.files)))
else:
width = 1


def selected(counts):
chosen = []
if show_lines:
chosen.append(counts[0])
if show_words:
chosen.append(counts[1])
if show_bytes:
chosen.append(counts[2])
return chosen


for counts, label in rows:
columns = " ".join(f"{value:{width}}" for value in selected(counts))
print(f"{columns} {label}")
Loading