Skip to content

Commit 93361aa

Browse files
committed
Implementing shell tools so that they behave like the real versions on a typical system: cat, ls, and wc.
1 parent 407b010 commit 93361aa

File tree

3 files changed

+153
-0
lines changed

3 files changed

+153
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { program } from "commander";
2+
import { promises as fs } from "node:fs";
3+
import process from "node:process";
4+
5+
program
6+
.name("read-files-content")
7+
.description("Read the content of a file (simulating cat command)")
8+
.option("-n, --number","Number of lines")
9+
.option("-b","Number of no-blanks lines")
10+
.argument("<path...>","The file path to process"); //file
11+
12+
program.parse();
13+
14+
const argv = program.args;
15+
16+
if (argv.length === 0) {
17+
console.error(`Expected file path(s),passed but got ${argv.length}.`);
18+
process.exit(1);
19+
}
20+
21+
//const path = argv[0];
22+
for (const path of argv){
23+
const option = program.opts();
24+
const content = await fs.readFile(path, "utf-8");
25+
if (option.number){
26+
// split content
27+
let lines = content.split(/\n/);
28+
// removes last line
29+
if (lines[lines.length - 1] === ""){
30+
lines = lines.slice(0,-1);
31+
}
32+
lines
33+
.map((line,index) => `${(index + 1).toString().padStart(6)}\t${line}`)
34+
.forEach(line => console.log(line))
35+
36+
} else if (option.b){
37+
let lines = content.split("\n");
38+
let linesCounter = 0;
39+
if (lines[lines.length - 1] === ""){
40+
lines = lines.slice(0,-1);
41+
}
42+
lines
43+
.map((line) => {
44+
if (line.trim().length > 0) {
45+
linesCounter++;
46+
return `${linesCounter.toString().padStart(6)}\t${line}`
47+
}else{
48+
return `${line}`
49+
}}
50+
)
51+
.forEach(line => console.log(line))
52+
}else {
53+
const output = content.endsWith("\n") ? content.slice(0,-1) : content;
54+
console.log(output);
55+
}
56+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { program } from "commander";
2+
import { promises as fs } from "node:fs";
3+
import process from "node:process";
4+
5+
program
6+
.name("list-files")
7+
.description("List files in a directory")
8+
.option("-1", "Show line by line")
9+
.option("-a, --all", "Show hidden files")
10+
.argument("[paths...]", "The directory paths",["."]);
11+
12+
program.parse();
13+
14+
const argv = program.args;
15+
16+
if (argv.length != 1){
17+
console.error(`Expected exactly 1 argument (a path) to be passed but got ${argv.length}`);
18+
process.exit(1);
19+
}
20+
const dirPath = argv[0];
21+
const options = program.opts();
22+
23+
const entries = await fs.readdir(dirPath)
24+
25+
const listFiles = entries.map((entry) => `${entry.padStart(6)}` )
26+
const noHidden = listFiles.filter(name => !name.startsWith('.'));
27+
28+
if (options.all && options[1]){
29+
console.log(listFiles.join('\n'));
30+
} else if (options.all) {
31+
console.log(listFiles.join(' '));
32+
} else if (options[1]){
33+
console.log(noHidden.join('\n'));
34+
} else {
35+
console.log(noHidden.join(' '));
36+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import {program} from "commander";
2+
import { promises as fs } from "node:fs";
3+
import process from "node:process";
4+
import { glob } from "glob";
5+
6+
program
7+
.name("content counter")
8+
.description("Counts lines, words, or characters in a file or files of a directory.")
9+
.option("-l,--lines","Options for l:Lines.")
10+
.option("-w,--words","Options for w:words.")
11+
.option("-c","Options for c:characters.")
12+
.argument("<path...>","The file or directory to process");
13+
14+
program.parse();
15+
16+
const argv = program.args;
17+
18+
const options = program.opts();
19+
20+
const result = [];
21+
let totalLines = 0;
22+
let totalWords = 0;
23+
let totalChars = 0;
24+
25+
for (const file of argv){
26+
27+
//1. Read each file
28+
29+
const content = await fs.readFile(file,"utf-8");
30+
// 2. calculate values
31+
const lines = content.split(/\n/g).length - 1 ;
32+
const words = content.trim().split(/\s+/).length;
33+
const chars = content.split("").length;
34+
// variable to pile up final line results according options
35+
const thisLine = [];
36+
if (options.lines){ thisLine.push(lines.toString().padStart(8)) };
37+
if (options.words){ thisLine.push(words.toString().padStart(8)) };
38+
if (options.c){ thisLine.push(chars.toString().padStart(8)) };
39+
if (!options.lines && !options.words && !options.c){ thisLine.push(lines.toString().padStart(8),words.toString().padStart(8),chars.toString().padStart(8)) };
40+
result.push(`${thisLine.join("")} ${file}`)
41+
// 3. add results
42+
// variables to accumulate the total
43+
totalLines += lines;
44+
totalWords += words;
45+
totalChars += chars;
46+
// 4. add total results if several files
47+
}
48+
if (argv.length>1){
49+
const finalLine = [];
50+
finalLine.push(totalLines.toString().padStart(8)),
51+
finalLine.push(totalWords.toString().padStart(8)),
52+
finalLine.push(totalChars.toString().padStart(8));
53+
result.push(`${finalLine.join("")} total`)
54+
}
55+
// 5. show results
56+
const output = result.join('\n');
57+
console.log(output)
58+
59+
60+
61+

0 commit comments

Comments
 (0)