From 0cf4afc46e4792ba1995bb0880bebc8371c475d5 Mon Sep 17 00:00:00 2001 From: mervereis Date: Mon, 27 Jul 2026 22:55:37 +0100 Subject: [PATCH] Implement cat, ls, and wc commands with line, word, and byte counting features --- implement-shell-tools/cat/cat.js | 50 +++++++++++++++++++ implement-shell-tools/ls/ls.js | 52 ++++++++++++++++++++ implement-shell-tools/wc/wc.js | 82 ++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 implement-shell-tools/cat/cat.js create mode 100644 implement-shell-tools/ls/ls.js create mode 100644 implement-shell-tools/wc/wc.js diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js new file mode 100644 index 000000000..cabd33ee2 --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,50 @@ +const fs = require("fs"); + +const args = process.argv.slice(2); + +let numberLines = false; +let numberNonBlank = false; +const files = []; + +for (const arg of args) { + if (arg === "-n") { + numberLines = true; + } else if (arg === "-b") { + numberNonBlank = true; + } else { + files.push(arg); + } +} + +if (numberNonBlank) { + numberLines = false; +} + +let lineNumber = 1; + +for (const file of files) { + try { + const contents = fs.readFileSync(file, "utf8"); + const lines = contents.split("\n"); + + lines.forEach((line, index) => { + const output = index < lines.length - 1 ? line + "\n" : line; + + if (numberNonBlank) { + if (line.trim() === "") { + process.stdout.write(output); + } else { + process.stdout.write(`${String(lineNumber).padStart(6)}\t${output}`); + lineNumber++; + } + } else if (numberLines) { + process.stdout.write(`${String(lineNumber).padStart(6)}\t${output}`); + lineNumber++; + } else { + process.stdout.write(output); + } + }); + } catch (err) { + console.error(`cat: ${file}: ${err.message}`); + } +} diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js new file mode 100644 index 000000000..01c4ded03 --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,52 @@ +const fs = require("fs"); + +const args = process.argv.slice(2); + +let onePerLine = false; +let showHidden = false; +let paths = []; + +for (let i = 0; i < args.length; i++) { + if (args[i] === "-1") { + onePerLine = true; + } else if (args[i] === "-a") { + showHidden = true; + } else { + paths.push(args[i]); + } +} +if (paths.length === 0) { + paths.push("."); +} + +for (let i = 0; i < paths.length; i++) { + let path = paths[i]; + + try { + if (fs.statSync(path).isFile()) { + console.log(path); + } else { + let files = fs.readdirSync(path); + + files.sort(); + + for (let j = 0; j < files.length; j++) { + let file = files[j]; + if (!showHidden && file.startsWith(".")) { + continue; + } + if (onePerLine) { + console.log(file); + } else { + process.stdout.write(file + " "); + } + } + + if (!onePerLine) { + console.log(); + } + } + } catch (error) { + console.log("Cannot access: " + path); + } +} diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js new file mode 100644 index 000000000..d54e0c02e --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,82 @@ +const fs = require("fs"); + +const args = process.argv.slice(2); + +let countLines = false; +let countWords = false; +let countBytes = false; + +let files = []; + +for (let arg of args) { + if (arg === "-l") { + countLines = true; + } else if (arg === "-w") { + countWords = true; + } else if (arg === "-c") { + countBytes = true; + } else { + files.push(arg); + } +} + +if (!countLines && !countWords && !countBytes) { + countLines = true; + countWords = true; + countBytes = true; +} + +let totalLines = 0; +let totalWords = 0; +let totalBytes = 0; +let filesCounted = 0; + +function countFile(fileName) { + try { + const content = fs.readFileSync(fileName, "utf8"); + let lines = content.split("\n").length - 1; + let words = content + .trim() + .split(/\s+/) + .filter((word) => word.length > 0).length; + let bytes = Buffer.byteLength(content); + totalLines += lines; + totalWords += words; + totalBytes += bytes; + filesCounted++; + let result = ""; + if (countLines) { + result += lines + " "; + } + if (countWords) { + result += words + " "; + } + if (countBytes) { + result += bytes + " "; + } + result += fileName; + console.log(result); + } catch (error) { + console.log("Cannot read file: " + fileName); + } +} + +for (let file of files) { + countFile(file); +} + +if (filesCounted > 1) { + let result = ""; + if (countLines) { + result += totalLines + " "; + } + if (countWords) { + result += totalWords + " "; + } + if (countBytes) { + result += totalBytes + " "; + } + result += "total"; + + console.log(result); +}