Skip to content

Commit 2e4a8ce

Browse files
feat(cat): implement full custom cat command with -n, -b options and wildcard expansion
1 parent 350ac88 commit 2e4a8ce

File tree

3 files changed

+101
-0
lines changed

3 files changed

+101
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env node
2+
const { program } = require("commander");
3+
const fs = require("fs");
4+
const path = require("path");
5+
6+
function expandWildcard(pattern) {
7+
const dir = path.dirname(pattern);
8+
const base = path.basename(pattern);
9+
10+
if (!base.includes("*")) return [pattern];
11+
12+
let files;
13+
try {
14+
files = fs.readdirSync(dir);
15+
} catch (e) {
16+
console.error(`cat: ${pattern}: No such directory`);
17+
return [];
18+
}
19+
20+
const regex = new RegExp("^" + base.replace(/\*/g, ".*") + "$");
21+
22+
return files
23+
.filter((f) => regex.test(f))
24+
.map((f) => path.join(dir, f));
25+
}
26+
27+
function printFile(filename, options) {
28+
let text;
29+
try {
30+
text = fs.readFileSync(filename, "utf-8");
31+
} catch {
32+
console.error(`cat: ${filename}: No such file`);
33+
return;
34+
}
35+
36+
const lines = text.split("\n");
37+
if (lines[lines.length - 1] === "") {
38+
lines.pop();
39+
}
40+
let counter = 1;
41+
42+
lines.forEach((line) => {
43+
if (options.numberAll) {
44+
console.log(`${String(counter).padStart(6)} ${line}`);
45+
counter++;
46+
} else if (options.numberNonempty) {
47+
if (line.trim() === "") {
48+
console.log("");
49+
} else {
50+
console.log(`${String(counter).padStart(6)} ${line}`);
51+
counter++;
52+
}
53+
} else {
54+
console.log(line);
55+
}
56+
});
57+
}
58+
59+
program
60+
.name("mycat")
61+
.description("A custom implementation of the cat command")
62+
.argument("<files...>", "files or wildcard patterns")
63+
.option("-n, --number-all", "number all lines")
64+
.option("-b, --number-nonempty", "number non-empty lines")
65+
.action((patterns, options) => {
66+
let allFiles = [];
67+
68+
patterns.forEach((p) => {
69+
allFiles = allFiles.concat(expandWildcard(p));
70+
});
71+
72+
allFiles.forEach((file) => printFile(file, options));
73+
});
74+
75+
program.parse();

implement-shell-tools/package-lock.json

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

implement-shell-tools/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"dependencies": {
3+
"commander": "^14.0.2"
4+
}
5+
}

0 commit comments

Comments
 (0)