From 0a3e5a577e9b61b0c6f2adc967063c7d75246fcd Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Sat, 25 Jul 2026 15:50:04 +0100 Subject: [PATCH 1/5] Add cat.js file and complete the first cat exercise. --- implement-shell-tools/cat/cat.js | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 implement-shell-tools/cat/cat.js diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js new file mode 100644 index 000000000..3e5d13132 --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,4 @@ +const fs = require ("fs"); +const args = process.argv.slice(2); +const content = fs.readFileSync(args[0], "utf-8") +console.log(content); \ No newline at end of file From 10353a9affbf5828dea418c17d7ddaa0ef8fc515 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Sun, 26 Jul 2026 16:27:47 +0100 Subject: [PATCH 2/5] Complete cat.js exercises. --- implement-shell-tools/cat/cat.js | 37 +++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 3e5d13132..8e0e33b8f 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -1,4 +1,35 @@ -const fs = require ("fs"); +const fs = require("fs"); + const args = process.argv.slice(2); -const content = fs.readFileSync(args[0], "utf-8") -console.log(content); \ No newline at end of file + +let mode = "normal"; + +if (args[0] === "-b") { + mode = "numberNonEmpty"; +} + +const files = args.slice(1); + +let lineNum = 1; + +for (const file of files) { + + const content = fs.readFileSync(file, "utf8"); + + const lines = content.trimEnd().split("\n"); + + for (const line of lines) { + + if (mode === "numberNonEmpty") { + + if (line !== "") { + console.log(lineNum + " " + line); + lineNum++; + } else { + console.log(line); + } + + } + + } +} From 8b8a2e6216f0d056d7920ce1ed8f001500cf544d Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Mon, 27 Jul 2026 12:41:49 +0100 Subject: [PATCH 3/5] Finilise the cat.js programm that works for the commands. --- implement-shell-tools/cat/cat.js | 36 +++++++++++++++++++------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 8e0e33b8f..9bb69a558 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -3,33 +3,41 @@ const fs = require("fs"); const args = process.argv.slice(2); let mode = "normal"; +let files = []; -if (args[0] === "-b") { +if (args[0] === "-n") { + mode = "number"; + files = args.slice(1); +} else if (args[0] === "-b") { mode = "numberNonEmpty"; + files = args.slice(1); +} else { + files = args; } -const files = args.slice(1); - let lineNum = 1; for (const file of files) { - const content = fs.readFileSync(file, "utf8"); - const lines = content.trimEnd().split("\n"); + const lines = content.replace(/\n$/, "").split("\n"); - for (const line of lines) { - - if (mode === "numberNonEmpty") { + if (mode === "normal") { + console.log(content); + continue; + } - if (line !== "") { - console.log(lineNum + " " + line); - lineNum++; + for (const line of lines) { + if (mode === "number") { + console.log(`${String(lineNum).padStart(6)} ${line}`); + lineNum++; + } else if (mode === "numberNonEmpty") { + if (line === "") { + console.log(""); } else { - console.log(line); + console.log(`${String(lineNum).padStart(6)} ${line}`); + lineNum++; } - } - } } From cc40d4b67d54cd6efe9efc822eb130d9f425ac34 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Mon, 27 Jul 2026 22:35:55 +0100 Subject: [PATCH 4/5] Complete implementing ls shell-tools. --- implement-shell-tools/ls/ls.js | 77 ++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 implement-shell-tools/ls/ls.js diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js new file mode 100644 index 000000000..dadc9b6ab --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,77 @@ +const fs = require("fs"); +const pathModule = require("path"); + +const args = process.argv.slice(2); + +let mode = "normal"; +let showHidden = false; +let paths = []; + +for (const arg of args) { + if (arg === "-1") { + mode = "onePerLine"; + } else if (arg === "-a") { + showHidden = true; + } else { + paths.push(arg); + } +} + +if (paths.length === 0) { + paths.push("."); +} + +function listDirectory(dir) { + let items = fs.readdirSync(dir); + + if (showHidden) { + items.unshift(".", ".."); + } else { + items = items.filter(item => !item.startsWith(".")); + } + + if (mode === "onePerLine") { + items.forEach(item => console.log(item)); + } else { + console.log(items.join(" ")); + } +} + +function expandWildcard(input) { + if (!input.includes("*")) { + return [input]; + } + const dir = pathModule.dirname(input); + const pattern = pathModule.basename(input); + const files = fs.readdirSync(dir); + + return files + .filter(file => { + if (pattern === "*") { + return showHidden || !file.startsWith("."); + } + + return file === pattern; + }) + .map(file => pathModule.join(dir, file)); +} + +for (const originalPath of paths) { + + const expandedPaths = expandWildcard(originalPath); + + for (const currentPath of expandedPaths) { + + const info = fs.statSync(currentPath); + + if (info.isDirectory()) { + listDirectory(currentPath); + } + + else if (info.isFile()) { + console.log(pathModule.basename(currentPath)); + } + + } + +} \ No newline at end of file From 0f47ad23743b1aca8b094d96406317c5ba88c8d9 Mon Sep 17 00:00:00 2001 From: Fithi Teklom Date: Mon, 27 Jul 2026 22:46:42 +0100 Subject: [PATCH 5/5] Complete implementing wc shell-tools. --- implement-shell-tools/wc/wc.js | 109 +++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 implement-shell-tools/wc/wc.js diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js new file mode 100644 index 000000000..398e1e6e4 --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,109 @@ +const fs = require("fs"); +const path = require("path"); + +const args = process.argv.slice(2); + +let countLines = false; +let countWords = false; +let countBytes = false; + +let files = []; + +for (const arg of args) { + if (arg === "-l") { + countLines = true; + } else if (arg === "-w") { + countWords = true; + } else if (arg === "-c") { + countBytes = true; + } else { + files.push(arg); + } +} + +function expandWildcard(filePath) { + if (!filePath.includes("*")) { + return [filePath]; + } + + const dir = path.dirname(filePath); + const files = fs.readdirSync(dir); + + return files.map(file => path.join(dir, file)); +} + +function getStats(filename) { + + const content = fs.readFileSync(filename, "utf8"); + + const lines = content.split("\n").length - 1; + + const words = content + .trim() + .split(/\s+/) + .filter(word => word.length > 0) + .length; + + const bytes = fs.statSync(filename).size; + + return { + lines, + words, + bytes + }; +} + +function printResult(stats, filename, showFilename = true) { + + let output = []; + + if (!countLines && !countWords && !countBytes) { + output.push(stats.lines); + output.push(stats.words); + output.push(stats.bytes); + } else { + if (countLines) { + output.push(stats.lines); + } + + if (countWords) { + output.push(stats.words); + } + + if (countBytes) { + output.push(stats.bytes); + } + } + + if (showFilename) { + output.push(filename); + } + + console.log(output.join(" ")); +} + +let allFiles = []; + +for (const file of files) { + allFiles.push(...expandWildcard(file)); +} + +let total = { + lines: 0, + words: 0, + bytes: 0 +}; + +for (const file of allFiles) { + + const stats = getStats(file); + + total.lines += stats.lines; + total.words += stats.words; + total.bytes += stats.bytes; + + printResult(stats, file); +} +if (allFiles.length > 1) { + printResult(total, "total"); +} \ No newline at end of file