diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js new file mode 100644 index 00000000..9aa0fabf --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,36 @@ +import { program } from "commander"; +import { promises as fs } from "node:fs"; + +program + .name("my-cat") + .description("Reimplementation of the Unix `cat` command with -n and -b support") + .option("-n", "number all lines") + .option("-b", "number non-empty lines") + .argument("", "files to read"); + +program.parse(); + +const options = program.opts(); +const filePaths = program.args; + +let lineNumber = 1; + +for (const filePath of filePaths) { + const content = await fs.readFile(filePath, "utf-8"); + + for (const line of content.split("\n")) { + if (options.n) { + console.log(`${String(lineNumber).padStart(6, ' ')} ${line}`); + lineNumber++; + } else if (options.b) { + if (line.trim()) { + console.log(`${String(lineNumber).padStart(6, ' ')} ${line}`); + lineNumber++; + } else { + console.log(""); + } + } else { + console.log(line); + } + } +} diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js new file mode 100644 index 00000000..cdccb524 --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,28 @@ +import { program } from "commander"; +import { promises as fs } from "node:fs"; + +program + .name("my-ls") + .description("Reimplementation of the Unix `ls` command with -1 and -a options") + .option("-1", "list one file per line") + .option("-a", "include hidden files") + .argument("[directory]", "directory to list"); + +program.parse(); + +const options = program.opts(); + +const directory = program.args[0] || "."; // Use current directory as default if no argument is provided + +const files = await fs.readdir(directory); + +const visibleFiles = options.a ? files : files.filter(file => !file.startsWith(".")); + +if (options["1"]) { + for (const file of visibleFiles) { + console.log(file); + } +} else { + console.log(visibleFiles.join(" ")); +} + \ No newline at end of file diff --git a/implement-shell-tools/package-lock.json b/implement-shell-tools/package-lock.json new file mode 100644 index 00000000..35bb20ea --- /dev/null +++ b/implement-shell-tools/package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "implement-shell-tools", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "implement-shell-tools", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^14.0.0" + } + }, + "node_modules/commander": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", + "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", + "license": "MIT", + "engines": { + "node": ">=20" + } + } + } +} diff --git a/implement-shell-tools/package.json b/implement-shell-tools/package.json new file mode 100644 index 00000000..809da8b9 --- /dev/null +++ b/implement-shell-tools/package.json @@ -0,0 +1,16 @@ +{ + "name": "implement-shell-tools", + "version": "1.0.0", + "description": "Your task is to re-implement shell tools you have used.", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "commander": "^14.0.0" + } +} diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js new file mode 100644 index 00000000..197d8d10 --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,55 @@ +import { program } from "commander"; +import { promises as fs } from "node:fs"; + +program + .name("my-wc") + .description("Reimplementation of the Unix `wc` command supporting -l, -w, and -c flags") + .option("-l", "show line count") + .option("-w", "show word count") + .option("-c", "show character count") + .argument("", "files to read"); + +program.parse(); + +const options = program.opts(); +const filePaths = program.args; + +function formatCounts(lines, words, chars, options) { + let result = ""; + + if (options.l || options.w || options.c) { + if (options.l) result += `${lines} `; + if (options.w) result += `${words} `; + if (options.c) result += `${chars} `; + } else { + result += `${lines} ${words} ${chars} `; + } + + return result; +} + +let totalLines = 0; +let totalWords = 0; +let totalChars = 0; + +for (const filePath of filePaths) { + const content = await fs.readFile(filePath, "utf-8"); + + const lineCount = (content.match(/\n/g) || []).length; + const wordCount = content.trim().split(/\s+/).length; + const charCount = content.length; + + totalLines += lineCount; + totalWords += wordCount; + totalChars += charCount; + + const output = formatCounts(lineCount, wordCount, charCount, options); + + console.log(`${output}${filePath}`); +} + +if (filePaths.length > 1) { + const totalOutput = formatCounts(totalLines, totalWords, totalChars, options); + + console.log(`${totalOutput}total`); +}