diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..9d00c88fe Binary files /dev/null and b/.DS_Store differ diff --git a/implement-shell-tools/.DS_Store b/implement-shell-tools/.DS_Store new file mode 100644 index 000000000..a00719516 Binary files /dev/null and b/implement-shell-tools/.DS_Store differ diff --git a/implement-shell-tools/cat/cat.mjs b/implement-shell-tools/cat/cat.mjs new file mode 100644 index 000000000..47651f179 --- /dev/null +++ b/implement-shell-tools/cat/cat.mjs @@ -0,0 +1,49 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; +import { program } from "commander"; + +program + .name("Cat") + .description("My version of cat command line tool") + .argument("", "Files to display") + .option("-n, --number", "Number all output lines") + .option("-b, --non-blank", "Number non empty output lines"); + +program.parse(); + +const { number, nonBlank } = program.opts(); +const filePaths = program.args; + +let lineNumber = 1; + +for (const filePath of filePaths) { + try { + const content = await fs.readFile(filePath, "utf-8"); + + if (!number && !nonBlank) { + process.stdout.write(content); + continue; + } + let text = content; + if (content.endsWith("\n")) { + text = content.slice(0, -1); + } + const lines = text.split("\n"); + + for (const line of lines) { + if (nonBlank) { + if (line == "") { + console.log(); + } else { + console.log(`${lineNumber}\t${line}`); + lineNumber++; + } + } else if (number) { + console.log(`${lineNumber}\t${line}`); + lineNumber++; + } + } + } catch (error) { + console.error(`${error}`); + } +} diff --git a/implement-shell-tools/ls/ls.mjs b/implement-shell-tools/ls/ls.mjs new file mode 100644 index 000000000..2c1574b4b --- /dev/null +++ b/implement-shell-tools/ls/ls.mjs @@ -0,0 +1,37 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; +import { program } from "commander"; + +program + .name("list") + .description("Implement my version of ls") + .argument("[paths...]", "The file path to process") + .option("-1, --one", "This list the item one per line") + .option("-a, --all", "This lists all of the files"); + +program.parse(); + +const { one, all } = program.opts(); +const paths = program.args; + +let targetDir = paths[0] || "."; + +try { + let files = await fs.readdir(targetDir); + + if (all) { + files = [".", "..", ...files].sort(); + } else { + files = files.filter((output) => !output.startsWith(".")).sort(); + } + + if (one) { + for (const file of files) { + console.log(file); + } + } else { + console.log(files.join(" ")); + } +} catch (error) { + console.error(`${error}`); +} diff --git a/implement-shell-tools/package-lock.json b/implement-shell-tools/package-lock.json new file mode 100644 index 000000000..5444e5c23 --- /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": "^15.0.0" + } + }, + "node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + } + } +} diff --git a/implement-shell-tools/package.json b/implement-shell-tools/package.json new file mode 100644 index 000000000..a05eb6f34 --- /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": "^15.0.0" + } +} diff --git a/implement-shell-tools/wc/sample-files/4.txt b/implement-shell-tools/wc/sample-files/4.txt new file mode 100644 index 000000000..e69de29bb diff --git a/implement-shell-tools/wc/wc.mjs b/implement-shell-tools/wc/wc.mjs new file mode 100644 index 000000000..65c86e9c5 --- /dev/null +++ b/implement-shell-tools/wc/wc.mjs @@ -0,0 +1,84 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; +import { program } from "commander"; + +program + .name("Word Count") + .description("my implementation of wc") + .argument("", "The file path to process") + .option("-l", "Count for the total number of lines") + .option("-c", "Count the total number of bytes") + .option("-w", "Count the total number of words"); + +program.parse(); + +let filePaths = program.args; +let options = program.opts(); +let noFlags = !options.l && !options.w && !options.c; + +let totalLines = 0; +let totalWords = 0; +let totalBytes = 0; + +for (const filePath of filePaths) { + try { + const content = await fs.readFile(filePath, "utf-8"); + const outputs = []; + + const lines = getLineCount(content); + const words = getWordCount(content); + const bytes = getByteCount(content); + + totalLines += lines; + totalWords += words; + totalBytes += bytes; + + if (noFlags || options.l) { + outputs.push(lines); + } + if (noFlags || options.w) { + outputs.push(words); + } + if (noFlags || options.c) { + outputs.push(bytes); + } + + outputs.push(filePath); + console.log(outputs.join("\t")); + } catch (err) { + console.error(`${err.message}`); + } +} + +if (filePaths.length > 1) { + const totalOutputs = []; + + if (noFlags || options.l) { + totalOutputs.push(totalLines); + } + if (noFlags || options.w) { + totalOutputs.push(totalWords); + } + if (noFlags || options.c) { + totalOutputs.push(totalBytes); + } + totalOutputs.push("total"); + console.log(totalOutputs.join("\t")); +} + +function getWordCount(text) { + const trimmed = text.trim(); + if (trimmed.length == 0) { + return 0; + } + return trimmed.split(/\s+/).length; +} + +function getLineCount(text) { + if (text.length == 0) return 0; + return text.split("\n").length - 1; +} + +function getByteCount(text) { + return Buffer.byteLength(text, "utf-8"); +}