diff --git a/implement-shell-tools/cat/README.md b/implement-shell-tools/cat/README.md index 7284a5e..384cb54 100644 --- a/implement-shell-tools/cat/README.md +++ b/implement-shell-tools/cat/README.md @@ -15,3 +15,8 @@ It must act the same as `cat` would, if run from the directory containing this R Matching any additional behaviours or flags are optional stretch goals. We recommend you start off supporting no flags, then add support for `-n`, then add support for `-b`. + +Run the Python implementation from this directory with `python cat.py sample-files/1.txt` +or `python cat.py -n sample-files/1.txt sample-files/2.txt`. Use `-b` to number +nonempty lines. Python 3 is required. Pass filenames explicitly if your shell +does not expand wildcards. diff --git a/implement-shell-tools/cat/cat.py b/implement-shell-tools/cat/cat.py new file mode 100644 index 0000000..82ea639 --- /dev/null +++ b/implement-shell-tools/cat/cat.py @@ -0,0 +1,34 @@ +"""Concatenate files, optionally numbering their lines.""" + +import argparse +from pathlib import Path +import sys + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("-n", action="store_true", help="number every line") + parser.add_argument("-b", action="store_true", help="number nonempty lines") + parser.add_argument("files", nargs="+") + args = parser.parse_args() + status = 0 + + for filename in args.files: + line_number = 1 + try: + with Path(filename).open(encoding="utf-8", newline="") as source: + for line in source: + number_line = args.n or (args.b and bool(line.strip())) + if number_line: + sys.stdout.write(f"{line_number:6}\t") + line_number += 1 + sys.stdout.write(line) + except (OSError, UnicodeError) as error: + print(f"cat: {filename}: {error}", file=sys.stderr) + status = 1 + + return status + + +if __name__ == "__main__": + sys.exit(main())