diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js new file mode 100644 index 00000000..91ec0984 --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,53 @@ +import process from "node:process"; +import {promises as fs} from "node:fs"; +import {program} from "commander"; + +program + .name("display-file-content") + .description("Output the content of a file to the terminal") + .argument("", "The file path to process") + .option("-n", "Number the output lines") + .option("-b","Number the non-blank output lines") + +program.parse(); + +const paths = program.args; + +const options = program.opts(); + +let lineNumber = 1; + +for (const path of paths) { + const filesContent = await fs.readFile(path, "utf-8"); + + const lines = filesContent.split("\n"); + + if (lines[lines.length - 1] === "") { + lines.pop(); + } + + for (let line of lines) { + if (options.n) { + process.stdout.write(`${lineNumber} ${line}\n`); + lineNumber++; + } else if (options.b) { + if (line != "") { + process.stdout.write(`${lineNumber} ${line}\n`); + lineNumber++; + } else { + process.stdout.write("\n"); + } + } else { + process.stdout.write(line + "\n"); + } + } +} + + + + + + + + + diff --git a/implement-shell-tools/cat/package-lock.json b/implement-shell-tools/cat/package-lock.json new file mode 100644 index 00000000..9ca092a6 --- /dev/null +++ b/implement-shell-tools/cat/package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "cat", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cat", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^14.0.2" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + } + } +} diff --git a/implement-shell-tools/cat/package.json b/implement-shell-tools/cat/package.json new file mode 100644 index 00000000..a6653b6b --- /dev/null +++ b/implement-shell-tools/cat/package.json @@ -0,0 +1,16 @@ +{ + "name": "cat", + "version": "1.0.0", + "description": "You should already be familiar with the `cat` command line tool.", + "main": "cat.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "module", + "dependencies": { + "commander": "^14.0.2" + } +} diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js new file mode 100644 index 00000000..d31d971b --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,48 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; +import { program } from "commander"; + +program + .name("list-files-in-directory") + .description("List all files and directories in a directory") + .argument("", "The file path to process") + .option("-1, --one", "Output one entry per line") + .option("-a", "List all files & directories, including hidden ones"); + +program.parse(); + +const path = program.args[0]; + +const options = program.opts(); + +if (!path) { + console.error("Error: No directory path was provided."); + process.exit(1); +} + +let directoryContent; + +try { + directoryContent = await fs.readdir(path); +} catch (err) { + console.error(`Error reading directory: ${err.message}`); + process.exit(1); +} + +let allContent = directoryContent; + +if (!options.a) { + allContent = directoryContent.filter(name => !name.startsWith(".")); +} + +for (const item of allContent) { + if (options.one) { + process.stdout.write(item + "\n"); + } else { + process.stdout.write(item + " "); + } + } + + + + diff --git a/implement-shell-tools/ls/package-lock.json b/implement-shell-tools/ls/package-lock.json new file mode 100644 index 00000000..771b618b --- /dev/null +++ b/implement-shell-tools/ls/package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "ls", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ls", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^14.0.2" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + } + } +} diff --git a/implement-shell-tools/ls/package.json b/implement-shell-tools/ls/package.json new file mode 100644 index 00000000..d227aaca --- /dev/null +++ b/implement-shell-tools/ls/package.json @@ -0,0 +1,16 @@ +{ + "name": "ls", + "version": "1.0.0", + "description": "You should already be familiar with the `ls` command line tool.", + "main": "ls.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "module", + "dependencies": { + "commander": "^14.0.2" + } +} diff --git a/implement-shell-tools/wc/package-lock.json b/implement-shell-tools/wc/package-lock.json new file mode 100644 index 00000000..1aff6316 --- /dev/null +++ b/implement-shell-tools/wc/package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "wc", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "wc", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^14.0.2" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + } + } +} diff --git a/implement-shell-tools/wc/package.json b/implement-shell-tools/wc/package.json new file mode 100644 index 00000000..b78a04c9 --- /dev/null +++ b/implement-shell-tools/wc/package.json @@ -0,0 +1,16 @@ +{ + "name": "wc", + "version": "1.0.0", + "description": "You should already be familiar with the `wc` command line tool.", + "main": "wc.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "module", + "dependencies": { + "commander": "^14.0.2" + } +} diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js new file mode 100644 index 00000000..67dae674 --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,90 @@ +import { program } from "commander"; +import { promises as fs } from "node:fs"; +import process from "node:process"; +import { stat } from "node:fs/promises"; + +program + .name("count-containing-lines-words-characters") + .description("Counts lines, words or characters in a file (or all files) inside a directory") + .option("-l, --line", "The number of lines in each file") + .option("-w, --word", "The number of words in each file") + .option("-c, --character", "The number of characters in each file") + .argument("", "The file path to process"); + +program.parse(); + +const argv = program.args; + +const options = program.opts(); + + +function counter(item) { + const lines = item.trim().split("\n").length; + const words = item.split(/\s+/).filter(Boolean).length; + const characters = item.length; + return { lines, words, characters }; +} + +let totalLines = 0; +let totalWords = 0; +let totalCharacters = 0; +let fileCount = 0; + +for (const path of argv) { + const pathInfo = await stat(path); + +if (pathInfo.isFile()) { + const content = await fs.readFile(path, "utf-8"); + const stats = counter(content); + if (options.line) { + console.log(`${stats.lines} ${path}`); + } else if (options.word) { + console.log(`${stats.words} ${path}`); + } else if (options.character) { + console.log(`${stats.characters} ${path}`); + } else { + console.log(`${stats.lines} ${stats.words} ${stats.characters} ${path}`); + } + + totalLines += stats.lines; + totalWords += stats.words; + totalCharacters += stats.characters; + fileCount++; + +} else if (pathInfo.isDirectory()) { + const files = await fs.readdir(path); + for (const file of files) { + const filePath = `${path}/${file}`; + const fileContent = await fs.readFile(filePath, "utf-8"); + const stats = counter(fileContent); + + if (options.line) { + console.log(`${stats.lines} ${filePath}`); + } else if (options.word) { + console.log(`${stats.words} ${filePath}`); + } else if (options.character) { + console.log(`${stats.characters} ${filePath}`); + } else { + console.log(`${stats.lines} ${stats.words} ${stats.characters} ${filePath}`); + } + + totalLines += stats.lines; + totalWords += stats.words; + totalCharacters += stats.characters; + fileCount++; + } +} + +} + +if (fileCount > 1) { + if (options.line) { + console.log(`${totalLines} total`); + } else if (options.word) { + console.log(`${totalWords} total`); + } else if (options.character) { + console.log(`${totalCharacters} total`); + } else { + console.log(`${totalLines} ${totalWords} ${totalCharacters} total`); + } +} \ No newline at end of file