From 78bdfd5f5130b16853693f87d5b920acfa710cda Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Tue, 28 Jul 2026 10:08:03 +0100 Subject: [PATCH 01/17] cat implemented --- implement-shell-tools/cat/cat.js | 46 ++++++++++++++++++++++++++++++++ 1 file changed, 46 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..e21ac51e0 --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,46 @@ +const fs = require("fs"); + +const arguments = process.argv; +const filePaths = arguments.slice(2); + +const index = arguments[1].lastIndexOf("/"); +const currentWorkingDirectory = arguments[1].slice(0, index + 1); + +let flag = filePaths[0]; +if (flag.charAt(0) == "-") { + flag = filePaths.shift(); +} + +function splitFile(fileName) { + const filePath = currentWorkingDirectory + fileName; + const text = fs.readFileSync(filePath, "utf8").trimEnd(); + return text.split("\n"); +} + +function printFile(lines) { + lines.forEach((line) => { + console.log(line); + }); +} + +function executeFlag(lines) { + if (flag === "-n") { + return lines.map((line, index) => `${String(index + 1).padStart(6, " ")} ${line}`); + } else if (flag === "-b") { + let lineNumber = 1; + return lines.map((line) => { + if (line === "") { + return `${line}`; + } + return `${String(lineNumber++).padStart(6, " ")} ${line}`; + }); + } else { + return lines; + } +} + +filePaths.forEach((filePath) => { + let lines = splitFile(filePath); + lines = executeFlag(lines); + printFile(lines); +}); From 60b323e23467c6d21b1abe736ddcb10bd41f8c4e Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Tue, 28 Jul 2026 20:10:51 +0100 Subject: [PATCH 02/17] cat updated --- implement-shell-tools/cat/cat.js | 77 +++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index e21ac51e0..e9dcd9147 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -1,46 +1,73 @@ const fs = require("fs"); const arguments = process.argv; -const filePaths = arguments.slice(2); +const userArguments = arguments.slice(2); const index = arguments[1].lastIndexOf("/"); const currentWorkingDirectory = arguments[1].slice(0, index + 1); -let flag = filePaths[0]; -if (flag.charAt(0) == "-") { - flag = filePaths.shift(); +const flags = userArguments + .filter((argument) => argument.startsWith("-")) + .map((argument) => argument.slice(1)) + .join(""); + +const flagHandlers = { + b: bFlag, + n: nFlag, +}; + +const fileNames = userArguments.filter((argument) => !argument.startsWith("-")); +let allFilesContents = []; + +readFiles(); +executeFlags(); +printLines(); + +function readFiles() { + fileNames.forEach((fileName) => { + fileContent = readFile(fileName); + allFilesContents.push(fileContent.split("\n")); + }); } -function splitFile(fileName) { +function readFile(fileName) { const filePath = currentWorkingDirectory + fileName; - const text = fs.readFileSync(filePath, "utf8").trimEnd(); - return text.split("\n"); + return fs.readFileSync(filePath, "utf8").trimEnd(); } -function printFile(lines) { - lines.forEach((line) => { - console.log(line); - }); +function executeFlags() { + for (const flag of flags) { + if (flagHandlers[flag]) { + allFilesContents = flagHandlers[flag](); + } else { + console.error(`cat: illegal option -- ${flag}\nusage: cat [-belnstuv] [file ...]`); + process.exit(1); + } + } } -function executeFlag(lines) { - if (flag === "-n") { - return lines.map((line, index) => `${String(index + 1).padStart(6, " ")} ${line}`); - } else if (flag === "-b") { +function bFlag() { + return allFilesContents.map((fileContent) => { let lineNumber = 1; - return lines.map((line) => { - if (line === "") { + return fileContent.map((line, index) => { + if (line == "") { return `${line}`; } return `${String(lineNumber++).padStart(6, " ")} ${line}`; }); - } else { - return lines; - } + }); +} + +function nFlag() { + return allFilesContents.map((fileContent) => { + return fileContent.map((line, index) => `${String(index + 1).padStart(6, " ")} ${line}`); + }); } -filePaths.forEach((filePath) => { - let lines = splitFile(filePath); - lines = executeFlag(lines); - printFile(lines); -}); +function printLines() { + allFilesContents.forEach((fileContent) => { + fileContent.forEach((line) => { + console.log(line); + }); + }); +} From 3a35a7a48f3d8a52b2c79ead79cfd7db0a1bc30d Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Wed, 29 Jul 2026 00:56:56 +0100 Subject: [PATCH 03/17] wc implemented --- implement-shell-tools/wc/wc.js | 141 +++++++++++++++++++++++++++++++++ 1 file changed, 141 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..9635e8e3f --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,141 @@ +const fs = require("fs"); +const { allowedNodeEnvironmentFlags } = require("process"); + +const arguments = process.argv; +const userArguments = arguments.slice(2); + +const index = arguments[1].lastIndexOf("/"); +const currentWorkingDirectory = arguments[1].slice(0, index + 1); + +const flags = userArguments + .filter((argument) => argument.startsWith("-")) + .map((argument) => argument.slice(1)) + .join(""); + +const flagHandlers = { + l: lFlag, + w: wFlag, + c: cFlag, +}; + +const metrics = ["lineCount", "wordCount", "byteSize"]; +const fileNames = userArguments.filter((argument) => !argument.startsWith("-")); +const allFilesData = []; + +extractFilesData(); +addTotals(); +const outputData = structuredClone(allFilesData); + +let deleted = false; +executeFlags(); +printOutput(); + +function extractFilesData() { + fileNames.forEach((fileName) => { + const fileData = {}; + fileData.name = fileName; + fileData.text = readFile(fileName); + fileData.lineCount = calculateLineCount(fileData.text); + fileData.wordCount = calculateWordCount(fileData.text); + fileData.byteSize = readByteSize(fileName); + + allFilesData.push(fileData); + }); +} + +function addTotals() { + if (allFilesData.length == 1) { + return; + } + const totalsData = { name: "total" }; + metrics.forEach((metric) => { + let sum = 0; + allFilesData.forEach((file) => { + sum += file[metric]; + }); + totalsData[metric] = sum; + }); + allFilesData.push(totalsData); +} + +function readFile(fileName) { + const filePath = currentWorkingDirectory + fileName; + return fs.readFileSync(filePath, "utf8").trimEnd(); +} + +function calculateLineCount(text) { + return text.split("\n").length; +} + +function calculateWordCount(text) { + return text.split(/\s+/).length; +} + +function readByteSize(fileName) { + return fs.statSync(currentWorkingDirectory + fileName).size; +} + +function executeFlags() { + for (const flag of flags) { + if (flagHandlers[flag]) { + allFilesContents = flagHandlers[flag](); + } else { + console.error(`wc: illegal option -- ${flag}\nusage: wc [-Lclmw] [file ...]`); + process.exit(1); + } + } +} + +function lFlag() { + deleteOutputs(); + allFilesData.forEach((sourceFile) => { + const targetFile = outputData.find((file) => file.name === sourceFile.name); + targetFile.lineCount = getIfTrue(sourceFile, "lineCount"); + }); +} + +function wFlag() { + deleteOutputs(); + allFilesData.forEach((sourceFile) => { + const targetFile = outputData.find((file) => file.name === sourceFile.name); + targetFile.wordCount = getIfTrue(sourceFile, "wordCount"); + }); +} + +function cFlag() { + deleteOutputs(); + allFilesData.forEach((sourceFile) => { + const targetFile = outputData.find((file) => file.name === sourceFile.name); + targetFile.byteSize = getIfTrue(sourceFile, "byteSize"); + }); +} + +function deleteOutputs() { + if (!deleted) { + outputData.forEach((file) => { + metrics.forEach((metric) => { + delete file[metric]; + }); + }); + } + deleted = true; +} + +function printOutput() { + outputs = []; + outputData.forEach((file) => { + let outputString = ""; + metrics.forEach((metric) => { + outputString += getIfTrue(file, metric); + }); + outputString += ` ${file.name}`; + console.log(outputString); + }); +} + +function getIfTrue(file, metric) { + if (file[metric]) { + return String(file[metric]).padStart(8, " "); + } + return ""; +} From 085224e36b79d11885b390b6ab7cbb165b1ff481 Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Thu, 30 Jul 2026 17:17:26 +0100 Subject: [PATCH 04/17] ls complete --- implement-shell-tools/ls/ls.js | 124 +++++++++++++++++++++++++++++++++ 1 file changed, 124 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..6f1113671 --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,124 @@ +const fs = require("fs"); +const { allowedNodeEnvironmentFlags } = require("process"); + +const args = process.argv; +const userArgs = args.slice(2); + +const index = args[1].lastIndexOf("/"); +const currentWorkingDirectory = args[1].slice(0, index); + +const flags = userArgs + .filter((arg) => arg.startsWith("-")) + .map((arg) => arg.slice(1)) + .join(""); + +const flagHandlers = { + 1: Flag1, + a: Flaga, +}; + +let printInList = false; +let showAll = false; + +const fsItems = userArgs.filter((arg) => !arg.startsWith("-")); +let dirArgs; +let fileArgs; +let outputString = ""; + +const rawData = fs.readdirSync(currentWorkingDirectory); + +checkArgsLength(); +executeFlags(); +filterFilesAndDirs(); +populateOutput(); +print(); + +function executeFlags() { + for (const flag of flags) { + if (flagHandlers[flag]) { + allFilesContents = flagHandlers[flag](); + } else { + console.error( + `ls: invalid option -- ${flag}\nusage: ls [-@ABCFGHILOPRSTUWXabcdefghiklmnopqrstuvwxy1%,] [--color=when] [-D format] [file ...]`, + ); + process.exit(1); + } + } +} + +function Flag1() { + if (printInList) { + outputString = outputString.replaceAll("\t", "\n"); + outputString = outputString.replaceAll("\n\n", "\n"); + } else { + printInList = true; + } +} + +function Flaga() { + showAll = true; +} + +function checkArgsLength() { + if (fsItems.length == 0) { + fsItems.push("."); + } +} + +function filterFilesAndDirs() { + dirArgs = fsItems.filter((p) => fs.statSync(currentWorkingDirectory + "/" + p).isDirectory()); + fileArgs = fsItems.filter((p) => !fs.statSync(currentWorkingDirectory + "/" + p).isDirectory()); + if (showAll == false) { + removeDotFiles(fileArgs); + } +} + +function populateOutput() { + if (fsItems.length == 1) { + fileArgs.forEach((file) => { + outputString += file + " "; + }); + dirArgs.forEach((dir) => { + outputString += dirOutput(dir); + }); + } else { + fileArgs.forEach((file) => { + outputString += file + "\t"; + }); + dirArgs.forEach((dir) => { + outputString += "\n\n" + dir + ":\n" + dirOutput(dir); + }); + } +} + +function dirOutput(dir) { + let contents = fs.readdirSync(currentWorkingDirectory + "/" + dir); + let outputStr = ""; + if (showAll) { + outputStr += ".\t..\t"; + } else { + for (let i = contents.length - 1; i >= 0; i--) { + contents = removeDotFiles(contents); + } + } + contents.forEach((item) => { + outputStr += item + "\t"; + }); + return outputStr; +} + +function removeDotFiles(fileList) { + for (let i = fileList.length - 1; i >= 0; i--) { + if (fileList[i][0] == ".") { + fileList.splice(i, 1); + } + } + return fileList; +} + +function print() { + if (printInList == true) { + Flag1(); + } + console.log(outputString.trimEnd()); +} From b28f41dbb8b34c4594b13b4dd36aee9b001e6ba8 Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Fri, 31 Jul 2026 03:27:27 +0100 Subject: [PATCH 05/17] remove unused code --- implement-shell-tools/ls/ls.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 6f1113671..8646dfef6 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -25,8 +25,6 @@ let dirArgs; let fileArgs; let outputString = ""; -const rawData = fs.readdirSync(currentWorkingDirectory); - checkArgsLength(); executeFlags(); filterFilesAndDirs(); From 7d6a2986197f28cce46160941144831353c63a0e Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Wed, 12 Aug 2026 04:21:24 +0100 Subject: [PATCH 06/17] updated eronious boolean in ls --- implement-shell-tools/ls/ls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 8646dfef6..0efb21dd6 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -115,7 +115,7 @@ function removeDotFiles(fileList) { } function print() { - if (printInList == true) { + if (printInList) { Flag1(); } console.log(outputString.trimEnd()); From fce72f0c63b83180ab45dc058314a49e83d63d22 Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Fri, 28 Aug 2026 06:28:08 +0100 Subject: [PATCH 07/17] updated ls so that data doesn't rely on global variables and is passed through functions as arguments - also fixed an if boolean --- implement-shell-tools/ls/ls.js | 133 ++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 61 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 0efb21dd6..08af6391f 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -1,17 +1,6 @@ const fs = require("fs"); const { allowedNodeEnvironmentFlags } = require("process"); -const args = process.argv; -const userArgs = args.slice(2); - -const index = args[1].lastIndexOf("/"); -const currentWorkingDirectory = args[1].slice(0, index); - -const flags = userArgs - .filter((arg) => arg.startsWith("-")) - .map((arg) => arg.slice(1)) - .join(""); - const flagHandlers = { 1: Flag1, a: Flaga, @@ -20,81 +9,106 @@ const flagHandlers = { let printInList = false; let showAll = false; -const fsItems = userArgs.filter((arg) => !arg.startsWith("-")); -let dirArgs; -let fileArgs; -let outputString = ""; +ls(process.argv); + +// ---------- + +function ls(args) { + const userArgs = getUserArgs(args); + const currentWorkingDirectory = getCurrentWorkingDirectory(args); + const fsItems = checkArgsLength(getFsItems(userArgs)); + + executeFlags(getFlags(userArgs)); + + const dirArgs = getDirArgs(fsItems, currentWorkingDirectory); + const fileArgs = getFileArgs(fsItems, currentWorkingDirectory); + + print(populateOutput(fsItems, dirArgs, fileArgs, currentWorkingDirectory)); +} + +function getUserArgs(args) { + return args.slice(2); +} + +function getFsItems(userArgs) { + return userArgs.filter((arg) => !arg.startsWith("-")); +} + +function getCurrentWorkingDirectory(args) { + const index = args[1].lastIndexOf("/"); + return args[1].slice(0, index); +} -checkArgsLength(); -executeFlags(); -filterFilesAndDirs(); -populateOutput(); -print(); +function getFlags(userArgs) { + return userArgs + .filter((arg) => arg.startsWith("-")) + .map((arg) => arg.slice(1)) + .join(""); +} -function executeFlags() { +function executeFlags(flags) { for (const flag of flags) { - if (flagHandlers[flag]) { - allFilesContents = flagHandlers[flag](); - } else { - console.error( - `ls: invalid option -- ${flag}\nusage: ls [-@ABCFGHILOPRSTUWXabcdefghiklmnopqrstuvwxy1%,] [--color=when] [-D format] [file ...]`, - ); - process.exit(1); - } + if (flagHandlers[flag]) flagHandlers[flag](); + else invalidFlagError(); } } -function Flag1() { - if (printInList) { - outputString = outputString.replaceAll("\t", "\n"); - outputString = outputString.replaceAll("\n\n", "\n"); - } else { - printInList = true; - } +function invalidFlagError() { + console.error( + `ls: invalid option -- ${flag}\nusage: ls [-@ABCFGHILOPRSTUWXabcdefghiklmnopqrstuvwxy1%,] [--color=when] [-D format] [file ...]`, + ); + process.exit(1); +} + +function Flag1(outputString) { + if (printInList) return outputString.replaceAll("\t", "\n").replaceAll("\n\n", "\n"); + else printInList = true; } function Flaga() { showAll = true; } -function checkArgsLength() { - if (fsItems.length == 0) { - fsItems.push("."); - } +function checkArgsLength(fsItems) { + if (fsItems.length == 0) fsItems.push("."); + return fsItems; } -function filterFilesAndDirs() { - dirArgs = fsItems.filter((p) => fs.statSync(currentWorkingDirectory + "/" + p).isDirectory()); - fileArgs = fsItems.filter((p) => !fs.statSync(currentWorkingDirectory + "/" + p).isDirectory()); - if (showAll == false) { - removeDotFiles(fileArgs); - } +function getDirArgs(fsItems, currentWorkingDirectory) { + return fsItems.filter((p) => fs.statSync(currentWorkingDirectory + "/" + p).isDirectory()); +} + +function getFileArgs(fsItems, currentWorkingDirectory) { + const fileArgs = fsItems.filter((p) => !fs.statSync(currentWorkingDirectory + "/" + p).isDirectory()); + if (showAll == false) removeDotFiles(fileArgs); + return fileArgs; } -function populateOutput() { +function populateOutput(fsItems, dirArgs, fileArgs, currentWorkingDirectory) { + let outputString = ""; if (fsItems.length == 1) { fileArgs.forEach((file) => { outputString += file + " "; }); dirArgs.forEach((dir) => { - outputString += dirOutput(dir); + outputString += dirOutput(dir, currentWorkingDirectory); }); } else { fileArgs.forEach((file) => { outputString += file + "\t"; }); dirArgs.forEach((dir) => { - outputString += "\n\n" + dir + ":\n" + dirOutput(dir); + outputString += "\n\n" + dir + ":\n" + dirOutput(dir, currentWorkingDirectory); }); } + return outputString; } -function dirOutput(dir) { +function dirOutput(dir, currentWorkingDirectory) { let contents = fs.readdirSync(currentWorkingDirectory + "/" + dir); let outputStr = ""; - if (showAll) { - outputStr += ".\t..\t"; - } else { + if (showAll) outputStr += ".\t..\t"; + else { for (let i = contents.length - 1; i >= 0; i--) { contents = removeDotFiles(contents); } @@ -107,16 +121,13 @@ function dirOutput(dir) { function removeDotFiles(fileList) { for (let i = fileList.length - 1; i >= 0; i--) { - if (fileList[i][0] == ".") { - fileList.splice(i, 1); - } + if (fileList[i][0] == ".") fileList.splice(i, 1); } return fileList; } -function print() { - if (printInList) { - Flag1(); - } - console.log(outputString.trimEnd()); +function print(outputString) { + let output = outputString; + if (printInList) output = Flag1(output); + console.log(output.trimEnd()); } From 14d4d3348fd4e49dcb7dcc9ff98bb24125aec158 Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Fri, 28 Aug 2026 06:36:59 +0100 Subject: [PATCH 08/17] updated flag a --- implement-shell-tools/ls/ls.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 08af6391f..967bbc1c8 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -60,9 +60,8 @@ function invalidFlagError() { process.exit(1); } -function Flag1(outputString) { - if (printInList) return outputString.replaceAll("\t", "\n").replaceAll("\n\n", "\n"); - else printInList = true; +function Flag1() { + printInList = true; } function Flaga() { @@ -128,6 +127,10 @@ function removeDotFiles(fileList) { function print(outputString) { let output = outputString; - if (printInList) output = Flag1(output); + if (printInList) output = makeList(output); console.log(output.trimEnd()); } + +function makeList(outputString) { + return outputString.replaceAll("\t", "\n").replaceAll("\n\n", "\n"); +} From 2b981ed488822916544cb4f275f79b8e652ca49a Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Fri, 28 Aug 2026 06:51:48 +0100 Subject: [PATCH 09/17] collapsed getuserargs function --- implement-shell-tools/ls/ls.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 967bbc1c8..30726c573 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -14,22 +14,18 @@ ls(process.argv); // ---------- function ls(args) { - const userArgs = getUserArgs(args); - const currentWorkingDirectory = getCurrentWorkingDirectory(args); - const fsItems = checkArgsLength(getFsItems(userArgs)); + const userArgs = args.slice(2); executeFlags(getFlags(userArgs)); + const fsItems = checkArgsLength(getFsItems(userArgs)); + const currentWorkingDirectory = getCurrentWorkingDirectory(args); const dirArgs = getDirArgs(fsItems, currentWorkingDirectory); const fileArgs = getFileArgs(fsItems, currentWorkingDirectory); print(populateOutput(fsItems, dirArgs, fileArgs, currentWorkingDirectory)); } -function getUserArgs(args) { - return args.slice(2); -} - function getFsItems(userArgs) { return userArgs.filter((arg) => !arg.startsWith("-")); } From fa7436b603d8aa92cc71ba6b3a4fce7594df13df Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Fri, 28 Aug 2026 16:17:31 +0100 Subject: [PATCH 10/17] rearranged some argument orders in ls --- implement-shell-tools/ls/ls.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 30726c573..3a6b45b51 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -18,12 +18,12 @@ function ls(args) { executeFlags(getFlags(userArgs)); - const fsItems = checkArgsLength(getFsItems(userArgs)); const currentWorkingDirectory = getCurrentWorkingDirectory(args); - const dirArgs = getDirArgs(fsItems, currentWorkingDirectory); - const fileArgs = getFileArgs(fsItems, currentWorkingDirectory); + const fsItems = checkArgsLength(getFsItems(userArgs)); + const dirArgs = getDirArgs(currentWorkingDirectory, fsItems); + const fileArgs = getFileArgs(currentWorkingDirectory, fsItems); - print(populateOutput(fsItems, dirArgs, fileArgs, currentWorkingDirectory)); + print(populateOutput(currentWorkingDirectory, fsItems, dirArgs, fileArgs)); } function getFsItems(userArgs) { @@ -69,17 +69,17 @@ function checkArgsLength(fsItems) { return fsItems; } -function getDirArgs(fsItems, currentWorkingDirectory) { +function getDirArgs(currentWorkingDirectory, fsItems) { return fsItems.filter((p) => fs.statSync(currentWorkingDirectory + "/" + p).isDirectory()); } -function getFileArgs(fsItems, currentWorkingDirectory) { +function getFileArgs(currentWorkingDirectory, fsItems) { const fileArgs = fsItems.filter((p) => !fs.statSync(currentWorkingDirectory + "/" + p).isDirectory()); if (showAll == false) removeDotFiles(fileArgs); return fileArgs; } -function populateOutput(fsItems, dirArgs, fileArgs, currentWorkingDirectory) { +function populateOutput(currentWorkingDirectory, fsItems, dirArgs, fileArgs) { let outputString = ""; if (fsItems.length == 1) { fileArgs.forEach((file) => { From d4720b18bf4e9d28519819c3b8fea3f1f783dae1 Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Fri, 28 Aug 2026 16:33:15 +0100 Subject: [PATCH 11/17] added comments to ls --- implement-shell-tools/cat/cat.js | 24 ++++++++++++++++------- implement-shell-tools/ls/ls.js | 33 ++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index e9dcd9147..e3097d6e9 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -47,15 +47,25 @@ function executeFlags() { } function bFlag() { - return allFilesContents.map((fileContent) => { + const resultFiles = []; + + for (const fileContent of allFilesContents) { + const formattedLines = []; let lineNumber = 1; - return fileContent.map((line, index) => { - if (line == "") { - return `${line}`; + + for (const line of fileContent) { + if (line === "") { + formattedLines.push(line); + } else { + const formattedLine = `${String(lineNumber++).padStart(6, " ")} ${line}`; + formattedLines.push(formattedLine); } - return `${String(lineNumber++).padStart(6, " ")} ${line}`; - }); - }); + } + + resultFiles.push(formattedLines); + } + + return resultFiles; } function nFlag() { diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 3a6b45b51..cb7106a09 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -26,14 +26,8 @@ function ls(args) { print(populateOutput(currentWorkingDirectory, fsItems, dirArgs, fileArgs)); } -function getFsItems(userArgs) { - return userArgs.filter((arg) => !arg.startsWith("-")); -} - -function getCurrentWorkingDirectory(args) { - const index = args[1].lastIndexOf("/"); - return args[1].slice(0, index); -} +// +// ===== Flag Handling ===== function getFlags(userArgs) { return userArgs @@ -60,10 +54,26 @@ function Flag1() { printInList = true; } +function makeList(outputString) { + return outputString.replaceAll("\t", "\n").replaceAll("\n\n", "\n"); +} + function Flaga() { showAll = true; } +// +// ===== Extracting data from arguments ===== + +function getCurrentWorkingDirectory(args) { + const index = args[1].lastIndexOf("/"); + return args[1].slice(0, index); +} + +function getFsItems(userArgs) { + return userArgs.filter((arg) => !arg.startsWith("-")); +} + function checkArgsLength(fsItems) { if (fsItems.length == 0) fsItems.push("."); return fsItems; @@ -79,6 +89,9 @@ function getFileArgs(currentWorkingDirectory, fsItems) { return fileArgs; } +// +// ===== Outputting Data ===== + function populateOutput(currentWorkingDirectory, fsItems, dirArgs, fileArgs) { let outputString = ""; if (fsItems.length == 1) { @@ -126,7 +139,3 @@ function print(outputString) { if (printInList) output = makeList(output); console.log(output.trimEnd()); } - -function makeList(outputString) { - return outputString.replaceAll("\t", "\n").replaceAll("\n\n", "\n"); -} From 5c6442916f947d588d10a7175a13be006ed3dc65 Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Fri, 28 Aug 2026 16:38:03 +0100 Subject: [PATCH 12/17] further added comments to ls --- implement-shell-tools/ls/ls.js | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index cb7106a09..f82a97728 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -1,18 +1,8 @@ const fs = require("fs"); const { allowedNodeEnvironmentFlags } = require("process"); -const flagHandlers = { - 1: Flag1, - a: Flaga, -}; - -let printInList = false; -let showAll = false; - -ls(process.argv); - -// ---------- - +// +// ===== ls Procedure ===== function ls(args) { const userArgs = args.slice(2); @@ -28,6 +18,13 @@ function ls(args) { // // ===== Flag Handling ===== +const flagHandlers = { + 1: Flag1, + a: Flaga, +}; + +let printInList = false; +let showAll = false; function getFlags(userArgs) { return userArgs @@ -63,8 +60,7 @@ function Flaga() { } // -// ===== Extracting data from arguments ===== - +// ===== Extracting Data From Arguments ===== function getCurrentWorkingDirectory(args) { const index = args[1].lastIndexOf("/"); return args[1].slice(0, index); @@ -90,8 +86,7 @@ function getFileArgs(currentWorkingDirectory, fsItems) { } // -// ===== Outputting Data ===== - +// ===== Populating and Outputting Data ===== function populateOutput(currentWorkingDirectory, fsItems, dirArgs, fileArgs) { let outputString = ""; if (fsItems.length == 1) { @@ -139,3 +134,7 @@ function print(outputString) { if (printInList) output = makeList(output); console.log(output.trimEnd()); } + +// +// ===== Run ls ===== +ls(process.argv); From 769706f84bbcf72d6b03963921e6c9dbe076d5b5 Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Fri, 28 Aug 2026 17:59:35 +0100 Subject: [PATCH 13/17] wc refactored --- implement-shell-tools/wc/wc.js | 174 ++++++++++++++++----------------- 1 file changed, 86 insertions(+), 88 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 9635e8e3f..aecd11cbb 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -1,64 +1,92 @@ const fs = require("fs"); const { allowedNodeEnvironmentFlags } = require("process"); -const arguments = process.argv; -const userArguments = arguments.slice(2); +const metrics = ["lineCount", "wordCount", "byteSize"]; +const displayedMetrics = []; + +// +// ===== wc Procedure ===== +function wc(args) { + const userArgs = args.slice(2); -const index = arguments[1].lastIndexOf("/"); -const currentWorkingDirectory = arguments[1].slice(0, index + 1); + executeFlags(getFlags(userArgs)); -const flags = userArguments - .filter((argument) => argument.startsWith("-")) - .map((argument) => argument.slice(1)) - .join(""); + const currentWorkingDirectory = getCurrentWorkingDirectory(args); + const fileNames = getFileNames(userArgs); + + const allFilesData = addTotals(extractFilesData(fileNames, currentWorkingDirectory)); + printOutput(allFilesData); +} +// +// ===== Flag Handling ===== const flagHandlers = { l: lFlag, w: wFlag, c: cFlag, }; -const metrics = ["lineCount", "wordCount", "byteSize"]; -const fileNames = userArguments.filter((argument) => !argument.startsWith("-")); -const allFilesData = []; +function getFlags(userArgs) { + return userArgs + .filter((arg) => arg.startsWith("-")) + .map((arg) => arg.slice(1)) + .join(""); +} + +function executeFlags(flags) { + for (const flag of flags) { + if (flagHandlers[flag]) flagHandlers[flag](); + else invalidFlagError(); + } +} + +function invalidFlagError() { + console.error(`wc: illegal option -- ${flag}\nusage: wc [-Lclmw] [file ...]`); + process.exit(1); +} + +function lFlag() { + displayedMetrics.push("lineCount"); +} + +function wFlag() { + displayedMetrics.push("wordCount"); +} + +function cFlag() { + displayedMetrics.push("byteSize"); +} + +// +// ===== Extracting Data From Arguments ===== +function getCurrentWorkingDirectory(args) { + const index = args[1].lastIndexOf("/"); + return args[1].slice(0, index + 1); +} -extractFilesData(); -addTotals(); -const outputData = structuredClone(allFilesData); +function getFileNames(userArgs) { + return userArgs.filter((argument) => !argument.startsWith("-")); +} -let deleted = false; -executeFlags(); -printOutput(); +// +// ===== Extracting Files Data ===== +function extractFilesData(fileNames, currentWorkingDirectory) { + const allFilesData = []; -function extractFilesData() { fileNames.forEach((fileName) => { const fileData = {}; fileData.name = fileName; - fileData.text = readFile(fileName); + fileData.text = readFile(fileName, currentWorkingDirectory); fileData.lineCount = calculateLineCount(fileData.text); fileData.wordCount = calculateWordCount(fileData.text); - fileData.byteSize = readByteSize(fileName); + fileData.byteSize = readByteSize(fileName, currentWorkingDirectory); allFilesData.push(fileData); }); + return allFilesData; } -function addTotals() { - if (allFilesData.length == 1) { - return; - } - const totalsData = { name: "total" }; - metrics.forEach((metric) => { - let sum = 0; - allFilesData.forEach((file) => { - sum += file[metric]; - }); - totalsData[metric] = sum; - }); - allFilesData.push(totalsData); -} - -function readFile(fileName) { +function readFile(fileName, currentWorkingDirectory) { const filePath = currentWorkingDirectory + fileName; return fs.readFileSync(filePath, "utf8").trimEnd(); } @@ -71,71 +99,41 @@ function calculateWordCount(text) { return text.split(/\s+/).length; } -function readByteSize(fileName) { +function readByteSize(fileName, currentWorkingDirectory) { return fs.statSync(currentWorkingDirectory + fileName).size; } -function executeFlags() { - for (const flag of flags) { - if (flagHandlers[flag]) { - allFilesContents = flagHandlers[flag](); - } else { - console.error(`wc: illegal option -- ${flag}\nusage: wc [-Lclmw] [file ...]`); - process.exit(1); - } - } -} - -function lFlag() { - deleteOutputs(); - allFilesData.forEach((sourceFile) => { - const targetFile = outputData.find((file) => file.name === sourceFile.name); - targetFile.lineCount = getIfTrue(sourceFile, "lineCount"); - }); -} - -function wFlag() { - deleteOutputs(); - allFilesData.forEach((sourceFile) => { - const targetFile = outputData.find((file) => file.name === sourceFile.name); - targetFile.wordCount = getIfTrue(sourceFile, "wordCount"); - }); -} +function addTotals(allFilesData) { + if (allFilesData.length == 1) return allFilesData; -function cFlag() { - deleteOutputs(); - allFilesData.forEach((sourceFile) => { - const targetFile = outputData.find((file) => file.name === sourceFile.name); - targetFile.byteSize = getIfTrue(sourceFile, "byteSize"); - }); -} - -function deleteOutputs() { - if (!deleted) { - outputData.forEach((file) => { - metrics.forEach((metric) => { - delete file[metric]; - }); + const totalsData = { name: "total" }; + metrics.forEach((metric) => { + let sum = 0; + allFilesData.forEach((file) => { + sum += file[metric]; }); - } - deleted = true; + totalsData[metric] = sum; + }); + allFilesData.push(totalsData); + return allFilesData; } -function printOutput() { - outputs = []; +// +// ===== Outputting Data ===== +function printOutput(outputData) { outputData.forEach((file) => { let outputString = ""; metrics.forEach((metric) => { - outputString += getIfTrue(file, metric); + if (displayedMetrics.length === 0 || displayedMetrics.includes(metric)) { + outputString += String(file[metric]).padStart(8, " "); + } }); + outputString += ` ${file.name}`; console.log(outputString); }); } -function getIfTrue(file, metric) { - if (file[metric]) { - return String(file[metric]).padStart(8, " "); - } - return ""; -} +// +// ===== Run wc ===== +wc(process.argv); From 65e60aea66eb93582a451691dae116bb24e6eae3 Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Fri, 28 Aug 2026 19:09:00 +0100 Subject: [PATCH 14/17] refactored cat --- implement-shell-tools/cat/cat.js | 121 +++++++++++++++++-------------- 1 file changed, 68 insertions(+), 53 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index e3097d6e9..6774beea9 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -1,83 +1,98 @@ const fs = require("fs"); -const arguments = process.argv; -const userArguments = arguments.slice(2); - -const index = arguments[1].lastIndexOf("/"); -const currentWorkingDirectory = arguments[1].slice(0, index + 1); - -const flags = userArguments - .filter((argument) => argument.startsWith("-")) - .map((argument) => argument.slice(1)) - .join(""); - -const flagHandlers = { - b: bFlag, - n: nFlag, -}; +// +// ===== cat Procedure ===== +function cat(args) { + const userArgs = args.slice(2); + const currentWorkingDirectory = getCurrentWorkingDirectory(args); + const fileNames = getFileNames(userArgs, currentWorkingDirectory); + + const allFilesContents = readFiles(fileNames, currentWorkingDirectory); + executeFlags(getFlags(userArgs), allFilesContents); + printLines(allFilesContents); +} -const fileNames = userArguments.filter((argument) => !argument.startsWith("-")); -let allFilesContents = []; +// +// ===== Extracting Data From Arguments ===== +function getCurrentWorkingDirectory(args) { + const index = args[1].lastIndexOf("/"); + return args[1].slice(0, index + 1); +} -readFiles(); -executeFlags(); -printLines(); +function getFileNames(userArgs) { + return userArgs.filter((argument) => !argument.startsWith("-")); +} -function readFiles() { +function readFiles(fileNames, currentWorkingDirectory) { + const allFilesContents = []; fileNames.forEach((fileName) => { - fileContent = readFile(fileName); + fileContent = readFile(fileName, currentWorkingDirectory); allFilesContents.push(fileContent.split("\n")); }); + return allFilesContents; } -function readFile(fileName) { +function readFile(fileName, currentWorkingDirectory) { const filePath = currentWorkingDirectory + fileName; return fs.readFileSync(filePath, "utf8").trimEnd(); } -function executeFlags() { +// +// ===== Flag Handling ===== +const flagHandlers = { + b: bFlag, + n: nFlag, +}; + +function getFlags(userArgs) { + return userArgs + .filter((arg) => arg.startsWith("-")) + .map((arg) => arg.slice(1)) + .join(""); +} + +function executeFlags(flags, allFilesContents) { for (const flag of flags) { - if (flagHandlers[flag]) { - allFilesContents = flagHandlers[flag](); - } else { - console.error(`cat: illegal option -- ${flag}\nusage: cat [-belnstuv] [file ...]`); - process.exit(1); - } + if (flagHandlers[flag]) flagHandlers[flag](allFilesContents, flags); + else invalidFlagError(); } } -function bFlag() { - const resultFiles = []; - - for (const fileContent of allFilesContents) { - const formattedLines = []; - let lineNumber = 1; +function invalidFlagError() { + console.error(`cat: illegal option -- ${flag}\nusage: cat [-belnstuv] [file ...]`); + process.exit(1); +} - for (const line of fileContent) { - if (line === "") { - formattedLines.push(line); - } else { - const formattedLine = `${String(lineNumber++).padStart(6, " ")} ${line}`; - formattedLines.push(formattedLine); +function bFlag(allFilesContents) { + let linenumber = 1; + allFilesContents.forEach((fileContent) => { + fileContent.forEach((line, index) => { + if (line !== "") { + fileContent[index] = `${String(linenumber).padStart(6, " ")} ${line}`; + linenumber += 1; } - } - - resultFiles.push(formattedLines); - } - - return resultFiles; + }); + }); } -function nFlag() { - return allFilesContents.map((fileContent) => { - return fileContent.map((line, index) => `${String(index + 1).padStart(6, " ")} ${line}`); - }); +function nFlag(allFilesContents, flags) { + if (!flags.includes("b")) { + allFilesContents.forEach((fileContent) => { + fileContent.forEach((line, index) => (fileContent[index] = `${String(index + 1).padStart(6, " ")} ${line}`)); + }); + } } -function printLines() { +// +// ==== Print Output ===== +function printLines(allFilesContents) { allFilesContents.forEach((fileContent) => { fileContent.forEach((line) => { console.log(line); }); }); } + +// +// ===== Run cat ===== +cat(process.argv); From efdd20b3a8e99a3ee6f4dfc611e325ef6522f1b5 Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Sat, 29 Aug 2026 05:56:28 +0100 Subject: [PATCH 15/17] updated getcwd --- implement-shell-tools/ls/ls.js | 8 ++++---- implement-shell-tools/wc/wc.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index f82a97728..ae03453b7 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -63,7 +63,7 @@ function Flaga() { // ===== Extracting Data From Arguments ===== function getCurrentWorkingDirectory(args) { const index = args[1].lastIndexOf("/"); - return args[1].slice(0, index); + return args[1].slice(0, index + 1); } function getFsItems(userArgs) { @@ -76,11 +76,11 @@ function checkArgsLength(fsItems) { } function getDirArgs(currentWorkingDirectory, fsItems) { - return fsItems.filter((p) => fs.statSync(currentWorkingDirectory + "/" + p).isDirectory()); + return fsItems.filter((p) => fs.statSync(currentWorkingDirectory + p).isDirectory()); } function getFileArgs(currentWorkingDirectory, fsItems) { - const fileArgs = fsItems.filter((p) => !fs.statSync(currentWorkingDirectory + "/" + p).isDirectory()); + const fileArgs = fsItems.filter((p) => !fs.statSync(currentWorkingDirectory + p).isDirectory()); if (showAll == false) removeDotFiles(fileArgs); return fileArgs; } @@ -108,7 +108,7 @@ function populateOutput(currentWorkingDirectory, fsItems, dirArgs, fileArgs) { } function dirOutput(dir, currentWorkingDirectory) { - let contents = fs.readdirSync(currentWorkingDirectory + "/" + dir); + let contents = fs.readdirSync(currentWorkingDirectory + dir); let outputStr = ""; if (showAll) outputStr += ".\t..\t"; else { diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index aecd11cbb..130c34778 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -33,9 +33,9 @@ function getFlags(userArgs) { .join(""); } -function executeFlags(flags) { +function executeFlags(flags, allFilesData) { for (const flag of flags) { - if (flagHandlers[flag]) flagHandlers[flag](); + if (flagHandlers[flag]) flagHandlers[flag](allFilesData); else invalidFlagError(); } } From 61a6eaa6c854a89a3182c01cc5a0a5f3129f8861 Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Sat, 29 Aug 2026 06:41:09 +0100 Subject: [PATCH 16/17] Add .venv to gitignore --- implement-cowsay/.gitignore | 1 + implement-cowsay/cow.py | 18 ++++++++++++++++++ implement-cowsay/requirements.txt | 1 + 3 files changed, 20 insertions(+) create mode 100644 implement-cowsay/.gitignore create mode 100644 implement-cowsay/cow.py create mode 100644 implement-cowsay/requirements.txt diff --git a/implement-cowsay/.gitignore b/implement-cowsay/.gitignore new file mode 100644 index 000000000..21d0b898f --- /dev/null +++ b/implement-cowsay/.gitignore @@ -0,0 +1 @@ +.venv/ diff --git a/implement-cowsay/cow.py b/implement-cowsay/cow.py new file mode 100644 index 000000000..236f4f3ce --- /dev/null +++ b/implement-cowsay/cow.py @@ -0,0 +1,18 @@ +import cowsay +import sys +import argparse + +parser = argparse.ArgumentParser( + prog="cowsay", + description="Make animals say things", +) + +parser.add_argument("--animal", choices=cowsay.char_names, help="The animal to be saying things.", default="cow") +parser.add_argument("message", nargs="*", help="The message to say.") + +args = parser.parse_args() + +if args.animal not in cowsay.char_names: + sys.exit(f"Unknown animal: {args.animal!r}. Choose from: {', '.join(cowsay.char_names)}") + +cowsay.char_funcs[args.animal](" ".join(args.message)) \ No newline at end of file diff --git a/implement-cowsay/requirements.txt b/implement-cowsay/requirements.txt new file mode 100644 index 000000000..c6b9ffd0e --- /dev/null +++ b/implement-cowsay/requirements.txt @@ -0,0 +1 @@ +cowsay From eeb4d7a01cba159a49faf3df1e611150adcc62ae Mon Sep 17 00:00:00 2001 From: Alex Jamshidi Date: Sat, 29 Aug 2026 06:51:46 +0100 Subject: [PATCH 17/17] removed implement shell tools files --- implement-shell-tools/cat/cat.js | 98 ---------------------- implement-shell-tools/ls/ls.js | 140 ------------------------------- implement-shell-tools/wc/wc.js | 139 ------------------------------ 3 files changed, 377 deletions(-) delete mode 100644 implement-shell-tools/cat/cat.js delete mode 100644 implement-shell-tools/ls/ls.js delete mode 100644 implement-shell-tools/wc/wc.js diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js deleted file mode 100644 index 6774beea9..000000000 --- a/implement-shell-tools/cat/cat.js +++ /dev/null @@ -1,98 +0,0 @@ -const fs = require("fs"); - -// -// ===== cat Procedure ===== -function cat(args) { - const userArgs = args.slice(2); - const currentWorkingDirectory = getCurrentWorkingDirectory(args); - const fileNames = getFileNames(userArgs, currentWorkingDirectory); - - const allFilesContents = readFiles(fileNames, currentWorkingDirectory); - executeFlags(getFlags(userArgs), allFilesContents); - printLines(allFilesContents); -} - -// -// ===== Extracting Data From Arguments ===== -function getCurrentWorkingDirectory(args) { - const index = args[1].lastIndexOf("/"); - return args[1].slice(0, index + 1); -} - -function getFileNames(userArgs) { - return userArgs.filter((argument) => !argument.startsWith("-")); -} - -function readFiles(fileNames, currentWorkingDirectory) { - const allFilesContents = []; - fileNames.forEach((fileName) => { - fileContent = readFile(fileName, currentWorkingDirectory); - allFilesContents.push(fileContent.split("\n")); - }); - return allFilesContents; -} - -function readFile(fileName, currentWorkingDirectory) { - const filePath = currentWorkingDirectory + fileName; - return fs.readFileSync(filePath, "utf8").trimEnd(); -} - -// -// ===== Flag Handling ===== -const flagHandlers = { - b: bFlag, - n: nFlag, -}; - -function getFlags(userArgs) { - return userArgs - .filter((arg) => arg.startsWith("-")) - .map((arg) => arg.slice(1)) - .join(""); -} - -function executeFlags(flags, allFilesContents) { - for (const flag of flags) { - if (flagHandlers[flag]) flagHandlers[flag](allFilesContents, flags); - else invalidFlagError(); - } -} - -function invalidFlagError() { - console.error(`cat: illegal option -- ${flag}\nusage: cat [-belnstuv] [file ...]`); - process.exit(1); -} - -function bFlag(allFilesContents) { - let linenumber = 1; - allFilesContents.forEach((fileContent) => { - fileContent.forEach((line, index) => { - if (line !== "") { - fileContent[index] = `${String(linenumber).padStart(6, " ")} ${line}`; - linenumber += 1; - } - }); - }); -} - -function nFlag(allFilesContents, flags) { - if (!flags.includes("b")) { - allFilesContents.forEach((fileContent) => { - fileContent.forEach((line, index) => (fileContent[index] = `${String(index + 1).padStart(6, " ")} ${line}`)); - }); - } -} - -// -// ==== Print Output ===== -function printLines(allFilesContents) { - allFilesContents.forEach((fileContent) => { - fileContent.forEach((line) => { - console.log(line); - }); - }); -} - -// -// ===== Run cat ===== -cat(process.argv); diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js deleted file mode 100644 index ae03453b7..000000000 --- a/implement-shell-tools/ls/ls.js +++ /dev/null @@ -1,140 +0,0 @@ -const fs = require("fs"); -const { allowedNodeEnvironmentFlags } = require("process"); - -// -// ===== ls Procedure ===== -function ls(args) { - const userArgs = args.slice(2); - - executeFlags(getFlags(userArgs)); - - const currentWorkingDirectory = getCurrentWorkingDirectory(args); - const fsItems = checkArgsLength(getFsItems(userArgs)); - const dirArgs = getDirArgs(currentWorkingDirectory, fsItems); - const fileArgs = getFileArgs(currentWorkingDirectory, fsItems); - - print(populateOutput(currentWorkingDirectory, fsItems, dirArgs, fileArgs)); -} - -// -// ===== Flag Handling ===== -const flagHandlers = { - 1: Flag1, - a: Flaga, -}; - -let printInList = false; -let showAll = false; - -function getFlags(userArgs) { - return userArgs - .filter((arg) => arg.startsWith("-")) - .map((arg) => arg.slice(1)) - .join(""); -} - -function executeFlags(flags) { - for (const flag of flags) { - if (flagHandlers[flag]) flagHandlers[flag](); - else invalidFlagError(); - } -} - -function invalidFlagError() { - console.error( - `ls: invalid option -- ${flag}\nusage: ls [-@ABCFGHILOPRSTUWXabcdefghiklmnopqrstuvwxy1%,] [--color=when] [-D format] [file ...]`, - ); - process.exit(1); -} - -function Flag1() { - printInList = true; -} - -function makeList(outputString) { - return outputString.replaceAll("\t", "\n").replaceAll("\n\n", "\n"); -} - -function Flaga() { - showAll = true; -} - -// -// ===== Extracting Data From Arguments ===== -function getCurrentWorkingDirectory(args) { - const index = args[1].lastIndexOf("/"); - return args[1].slice(0, index + 1); -} - -function getFsItems(userArgs) { - return userArgs.filter((arg) => !arg.startsWith("-")); -} - -function checkArgsLength(fsItems) { - if (fsItems.length == 0) fsItems.push("."); - return fsItems; -} - -function getDirArgs(currentWorkingDirectory, fsItems) { - return fsItems.filter((p) => fs.statSync(currentWorkingDirectory + p).isDirectory()); -} - -function getFileArgs(currentWorkingDirectory, fsItems) { - const fileArgs = fsItems.filter((p) => !fs.statSync(currentWorkingDirectory + p).isDirectory()); - if (showAll == false) removeDotFiles(fileArgs); - return fileArgs; -} - -// -// ===== Populating and Outputting Data ===== -function populateOutput(currentWorkingDirectory, fsItems, dirArgs, fileArgs) { - let outputString = ""; - if (fsItems.length == 1) { - fileArgs.forEach((file) => { - outputString += file + " "; - }); - dirArgs.forEach((dir) => { - outputString += dirOutput(dir, currentWorkingDirectory); - }); - } else { - fileArgs.forEach((file) => { - outputString += file + "\t"; - }); - dirArgs.forEach((dir) => { - outputString += "\n\n" + dir + ":\n" + dirOutput(dir, currentWorkingDirectory); - }); - } - return outputString; -} - -function dirOutput(dir, currentWorkingDirectory) { - let contents = fs.readdirSync(currentWorkingDirectory + dir); - let outputStr = ""; - if (showAll) outputStr += ".\t..\t"; - else { - for (let i = contents.length - 1; i >= 0; i--) { - contents = removeDotFiles(contents); - } - } - contents.forEach((item) => { - outputStr += item + "\t"; - }); - return outputStr; -} - -function removeDotFiles(fileList) { - for (let i = fileList.length - 1; i >= 0; i--) { - if (fileList[i][0] == ".") fileList.splice(i, 1); - } - return fileList; -} - -function print(outputString) { - let output = outputString; - if (printInList) output = makeList(output); - console.log(output.trimEnd()); -} - -// -// ===== Run ls ===== -ls(process.argv); diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js deleted file mode 100644 index 130c34778..000000000 --- a/implement-shell-tools/wc/wc.js +++ /dev/null @@ -1,139 +0,0 @@ -const fs = require("fs"); -const { allowedNodeEnvironmentFlags } = require("process"); - -const metrics = ["lineCount", "wordCount", "byteSize"]; -const displayedMetrics = []; - -// -// ===== wc Procedure ===== -function wc(args) { - const userArgs = args.slice(2); - - executeFlags(getFlags(userArgs)); - - const currentWorkingDirectory = getCurrentWorkingDirectory(args); - const fileNames = getFileNames(userArgs); - - const allFilesData = addTotals(extractFilesData(fileNames, currentWorkingDirectory)); - printOutput(allFilesData); -} - -// -// ===== Flag Handling ===== -const flagHandlers = { - l: lFlag, - w: wFlag, - c: cFlag, -}; - -function getFlags(userArgs) { - return userArgs - .filter((arg) => arg.startsWith("-")) - .map((arg) => arg.slice(1)) - .join(""); -} - -function executeFlags(flags, allFilesData) { - for (const flag of flags) { - if (flagHandlers[flag]) flagHandlers[flag](allFilesData); - else invalidFlagError(); - } -} - -function invalidFlagError() { - console.error(`wc: illegal option -- ${flag}\nusage: wc [-Lclmw] [file ...]`); - process.exit(1); -} - -function lFlag() { - displayedMetrics.push("lineCount"); -} - -function wFlag() { - displayedMetrics.push("wordCount"); -} - -function cFlag() { - displayedMetrics.push("byteSize"); -} - -// -// ===== Extracting Data From Arguments ===== -function getCurrentWorkingDirectory(args) { - const index = args[1].lastIndexOf("/"); - return args[1].slice(0, index + 1); -} - -function getFileNames(userArgs) { - return userArgs.filter((argument) => !argument.startsWith("-")); -} - -// -// ===== Extracting Files Data ===== -function extractFilesData(fileNames, currentWorkingDirectory) { - const allFilesData = []; - - fileNames.forEach((fileName) => { - const fileData = {}; - fileData.name = fileName; - fileData.text = readFile(fileName, currentWorkingDirectory); - fileData.lineCount = calculateLineCount(fileData.text); - fileData.wordCount = calculateWordCount(fileData.text); - fileData.byteSize = readByteSize(fileName, currentWorkingDirectory); - - allFilesData.push(fileData); - }); - return allFilesData; -} - -function readFile(fileName, currentWorkingDirectory) { - const filePath = currentWorkingDirectory + fileName; - return fs.readFileSync(filePath, "utf8").trimEnd(); -} - -function calculateLineCount(text) { - return text.split("\n").length; -} - -function calculateWordCount(text) { - return text.split(/\s+/).length; -} - -function readByteSize(fileName, currentWorkingDirectory) { - return fs.statSync(currentWorkingDirectory + fileName).size; -} - -function addTotals(allFilesData) { - if (allFilesData.length == 1) return allFilesData; - - const totalsData = { name: "total" }; - metrics.forEach((metric) => { - let sum = 0; - allFilesData.forEach((file) => { - sum += file[metric]; - }); - totalsData[metric] = sum; - }); - allFilesData.push(totalsData); - return allFilesData; -} - -// -// ===== Outputting Data ===== -function printOutput(outputData) { - outputData.forEach((file) => { - let outputString = ""; - metrics.forEach((metric) => { - if (displayedMetrics.length === 0 || displayedMetrics.includes(metric)) { - outputString += String(file[metric]).padStart(8, " "); - } - }); - - outputString += ` ${file.name}`; - console.log(outputString); - }); -} - -// -// ===== Run wc ===== -wc(process.argv);