Skip to content

Commit 0bc2cfa

Browse files
committed
cat,ls,wc review
1 parent 407b010 commit 0bc2cfa

File tree

3 files changed

+177
-0
lines changed

3 files changed

+177
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env node
2+
import { program } from "commander";
3+
import { promises as fs } from "node:fs";
4+
5+
// Setup CLI
6+
program
7+
.name("cat")
8+
.description("Concatenate files and print on the standard output")
9+
.option("-n, --number", "number all output lines")
10+
.option("-b, --number-nonblank", "number nonempty output lines")
11+
.argument("<path...>", "file(s) to read");
12+
13+
program.parse();
14+
15+
const files = program.args;
16+
const { number, numberNonblank } = program.opts();
17+
18+
// Validate input
19+
if (files.length === 0) {
20+
console.error("cat: missing file operand");
21+
process.exit(1);
22+
}
23+
24+
let lineNumber = 1;
25+
26+
// Helper to print lines with optional numbering
27+
function printLine(line, shouldNumber) {
28+
if (shouldNumber) {
29+
console.log(`${String(lineNumber).padStart(6)}\t${line}`);
30+
lineNumber++;
31+
} else {
32+
console.log(line);
33+
}
34+
}
35+
36+
for (const file of files) {
37+
let content;
38+
try {
39+
content = await fs.readFile(file, "utf8");
40+
} catch (err) {
41+
console.error(`cat: ${file}: ${err.message}`);
42+
continue;
43+
}
44+
45+
const lines = content.split("\n");
46+
47+
for (let i = 0; i < lines.length; i++) {
48+
const line = lines[i];
49+
50+
// Avoid printing an extra line if file ends with \n
51+
if (i === lines.length - 1 && line === "") {
52+
break;
53+
}
54+
55+
const isBlank = line.trim() === "";
56+
57+
if (numberNonblank) {
58+
printLine(line, !isBlank);
59+
} else if (number) {
60+
printLine(line, true);
61+
} else {
62+
printLine(line, false);
63+
}
64+
}
65+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/usr/bin/env node
2+
import { program } from "commander";
3+
import fs from "fs";
4+
import path from "path";
5+
6+
// Define CLI
7+
program
8+
.name("ls-clone")
9+
.description("A simple implementation of ls")
10+
.option("-1", "list one file per line")
11+
.option("-a", "include hidden files")
12+
.argument("[dirs...]", "directories to list", "."); // default is current dir
13+
14+
program.parse();
15+
16+
const options = program.opts();
17+
const dirs = program.args.length ? program.args : ["."];
18+
const onePerLine = options["1"];
19+
const showAll = options.a;
20+
21+
for (const dir of dirs) {
22+
let files;
23+
try {
24+
files = fs.readdirSync(dir);
25+
} catch (err) {
26+
console.error(`ls-clone: cannot access '${dir}': No such file or directory`);
27+
continue;
28+
}
29+
30+
if (!showAll) {
31+
files = files.filter(name => !name.startsWith("."));
32+
}
33+
34+
// Output
35+
if (onePerLine) {
36+
files.forEach(f => console.log(f));
37+
} else {
38+
console.log(files.join(" "));
39+
}
40+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env node
2+
import { program } from "commander";
3+
import { promises as fs } from "node:fs";
4+
import process from "node:process";
5+
6+
// Setup CLI
7+
program
8+
.name("wc-clone")
9+
.description("A simplified implementation of the wc command")
10+
.option("-l", "count lines")
11+
.option("-w", "count words")
12+
.option("-c", "count bytes")
13+
.argument("[files...]", "files to process");
14+
15+
program.parse();
16+
17+
const options = program.opts();
18+
const files = program.args;
19+
20+
if (files.length === 0) {
21+
console.error("Please provide at least one file.");
22+
process.exit(1);
23+
}
24+
25+
// Count lines, words, bytes
26+
function countContent(content) {
27+
const lines = content.split("\n").length;
28+
const words = content.trim().split(/\s+/).filter(Boolean).length;
29+
const bytes = Buffer.byteLength(content, "utf-8");
30+
return { lines, words, bytes };
31+
}
32+
33+
// Format output consistently
34+
function formatOutput(counts, label = "") {
35+
const showAll = !options.l && !options.w && !options.c;
36+
const parts = [];
37+
38+
if (options.l || showAll) parts.push(counts.lines.toString().padStart(8));
39+
if (options.w || showAll) parts.push(counts.words.toString().padStart(8));
40+
if (options.c || showAll) parts.push(counts.bytes.toString().padStart(8));
41+
42+
if (label) parts.push(label);
43+
44+
return parts.join(" ");
45+
}
46+
47+
(async () => {
48+
let total = { lines: 0, words: 0, bytes: 0 };
49+
const multipleFiles = files.length > 1;
50+
51+
for (const file of files) {
52+
let content;
53+
try {
54+
content = await fs.readFile(file, "utf-8");
55+
} catch {
56+
console.error(`wc-clone: cannot open '${file}': No such file`);
57+
continue;
58+
}
59+
60+
const counts = countContent(content);
61+
62+
total.lines += counts.lines;
63+
total.words += counts.words;
64+
total.bytes += counts.bytes;
65+
66+
console.log(formatOutput(counts, file));
67+
}
68+
69+
if (multipleFiles) {
70+
console.log(formatOutput(total, "total"));
71+
}
72+
})();

0 commit comments

Comments
 (0)