Skip to content

Commit e20c156

Browse files
Implement ls and wc command line tools in Python
1 parent b5089a2 commit e20c156

4 files changed

Lines changed: 82 additions & 0 deletions

File tree

‎implement-shell-tools/ls/README.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ It must act the same as `ls` would, if run from the directory containing this RE
1313
Matching any additional behaviours or flags are optional stretch goals.
1414

1515
We recommend you start off supporting just `-1`, then adding support for `-a`.
16+
17+
Run the Python implementation from this directory with `python ls.py -1 sample-files`
18+
or `python ls.py -1 -a sample-files`. Python 3 is required.

‎implement-shell-tools/ls/ls.py‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""List directory entries, one per line."""
2+
3+
import argparse
4+
from pathlib import Path
5+
import sys
6+
7+
8+
def main():
9+
parser = argparse.ArgumentParser(description=__doc__)
10+
parser.add_argument("-1", action="store_true", help="print one entry per line")
11+
parser.add_argument("-a", "--all", action="store_true", help="include hidden entries")
12+
parser.add_argument("directory", nargs="?", default=".")
13+
args = parser.parse_args()
14+
15+
try:
16+
entries = sorted(Path(args.directory).iterdir(), key=lambda entry: entry.name)
17+
for entry in entries:
18+
if args.all or not entry.name.startswith("."):
19+
print(entry.name)
20+
except OSError as error:
21+
print(f"ls: {error}", file=sys.stderr)
22+
return 1
23+
return 0
24+
25+
26+
if __name__ == "__main__":
27+
sys.exit(main())

‎implement-shell-tools/wc/README.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@ It must act the same as `wc` would, if run from the directory containing this RE
1515
Matching any additional behaviours or flags are optional stretch goals.
1616

1717
We recommend you start off supporting no flags for one file, then add support for multiple files, then add support for the flags.
18+
19+
Run the Python implementation from this directory with `python wc.py sample-files/1.txt`
20+
or `python wc.py -l sample-files/3.txt`. Multiple filenames and combined count
21+
flags are supported. Expand wildcards in your shell, or pass filenames explicitly
22+
if your shell does not expand them. Python 3 is required.

‎implement-shell-tools/wc/wc.py‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Count lines, words, and bytes in files."""
2+
3+
import argparse
4+
from pathlib import Path
5+
import sys
6+
7+
8+
def count_file(filename):
9+
text = Path(filename).read_bytes().decode("utf-8")
10+
return len(text.splitlines()), len(text.split()), len(text)
11+
12+
13+
def main():
14+
parser = argparse.ArgumentParser(description=__doc__)
15+
parser.add_argument("-l", action="store_true", help="print line counts")
16+
parser.add_argument("-w", action="store_true", help="print word counts")
17+
parser.add_argument("-c", action="store_true", help="print byte counts")
18+
parser.add_argument("files", nargs="+")
19+
args = parser.parse_args()
20+
selected = [args.l, args.w, args.c]
21+
if not any(selected):
22+
selected = [True, True, True]
23+
24+
def print_counts(counts, label):
25+
values = [str(value) for value, enabled in zip(counts, selected) if enabled]
26+
print(" ".join([*values, label]))
27+
28+
totals = [0, 0, 0]
29+
successful = 0
30+
status = 0
31+
for filename in args.files:
32+
try:
33+
counts = count_file(filename)
34+
except (OSError, UnicodeError) as error:
35+
print(f"wc: {filename}: {error}", file=sys.stderr)
36+
status = 1
37+
continue
38+
print_counts(counts, filename)
39+
totals = [total + value for total, value in zip(totals, counts)]
40+
successful += 1
41+
if successful > 1:
42+
print_counts(totals, "total")
43+
return status
44+
45+
46+
if __name__ == "__main__":
47+
sys.exit(main())

0 commit comments

Comments
 (0)