Skip to content

Commit cb086a0

Browse files
committed
Implement cat in JavaScript
1 parent 0b0eefb commit cb086a0

1 file changed

Lines changed: 58 additions & 0 deletions

File tree

‎implement-shell-tools/cat/cat.mjs‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import process from "node:process";
2+
import { promises as fs } from "node:fs";
3+
import { parseArgs } from "node:util";
4+
5+
const { values, positionals } = parseArgs({
6+
options: {
7+
number: { type: "boolean", short: "n", default: false },
8+
"number-nonblank": { type: "boolean", short: "b", default: false },
9+
},
10+
allowPositionals: true,
11+
});
12+
13+
const numberAll = values.number;
14+
const numberNonBlank = values["number-nonblank"];
15+
16+
if (positionals.length === 0) {
17+
console.error("Usage: node cat.js [-n] [-b] <path>...");
18+
process.exit(1);
19+
}
20+
21+
let lineNumber = 1;
22+
23+
for (const path of positionals) {
24+
let content;
25+
try {
26+
content = await fs.readFile(path, "utf-8");
27+
} catch {
28+
console.error(`cat: ${path}: No such file or directory`);
29+
process.exitCode = 1;
30+
continue;
31+
}
32+
33+
if (!numberAll && !numberNonBlank) {
34+
process.stdout.write(content);
35+
continue;
36+
}
37+
38+
const lines = content.split("\n");
39+
const endsWithNewline = lines[lines.length - 1] === "";
40+
if (endsWithNewline) {
41+
lines.pop();
42+
}
43+
44+
for (let i = 0; i < lines.length; i++) {
45+
const line = lines[i];
46+
const isLastLine = i === lines.length - 1;
47+
const lineEnding = !isLastLine || endsWithNewline ? "\n" : "";
48+
49+
if (numberNonBlank && line === "") {
50+
process.stdout.write(lineEnding);
51+
} else {
52+
process.stdout.write(
53+
`${String(lineNumber).padStart(6)}\t${line}${lineEnding}`,
54+
);
55+
lineNumber++;
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)