diff --git a/implement-shell-tools/.gitignore b/implement-shell-tools/.gitignore new file mode 100644 index 000000000..1d17dae13 --- /dev/null +++ b/implement-shell-tools/.gitignore @@ -0,0 +1 @@ +.venv diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js new file mode 100644 index 000000000..c0a26279f --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,44 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; + +const argv = process.argv.slice(2); + +const showNumbers = argv.includes("-n"); +const showNonBlankNumbers = argv.includes("-b"); + +const filePaths = argv.filter((arg) => !arg.startsWith("-")); + +const flagsUsed = argv.filter((arg) => arg.startsWith("-")); +const supportedFlags = ["-n", "-b"]; +for (const flag of flagsUsed) { + if (!supportedFlags.includes(flag)) { + console.error(`Invalid option: please try "-n or "-b"`); + process.exit(1); + } +} + +let counterLines = 1; + +for (const path of filePaths) { + try { + const content = await fs.readFile(path, "utf-8"); +. + const splitLines = content.split("\n"); + + splitLines.forEach((line) => { + let prefix = ""; + + if (showNonBlankNumbers) { + if (line.trim() !== "") { + prefix = `${counterLines++} `; + } + } else if (showNumbers) { + prefix = `${counterLines++} `; + } + console.log(`${prefix}${line}`); + }); + } catch (error) { + console.error(`Error ${path}: ${error.message}`); + process.exit(1); + } +} diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js new file mode 100644 index 000000000..1e30c42a8 --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,27 @@ +import fs from "node:fs"; +import process from "node:process"; + +const argv = process.argv.slice(2); + +const filePaths = argv.filter((arg) => !arg.startsWith("-")); +const showHiddenFiles = argv.includes("-a"); + +if (filePaths.length > 1) { + console.error("Error: This version only supports one directory path a time."); + process.exit(1); +} + +const target = filePaths[0] || "."; + +const files = fs.readdirSync(target); + +let filteredFIles = files; +if (!showHiddenFiles) { + filteredFIles = files.filter((file) => !file.startsWith(".")); +} else { + filteredFIles = [".", "..", ...files]; +} + +filteredFIles.forEach((file) => { + console.log(file); +}); diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js new file mode 100644 index 000000000..f10faf9e4 --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,67 @@ +import process, { exit } from "node:process"; +import fs from "node:fs"; + +const argv = process.argv.slice(2); + +let showWords = argv.includes("-w"); +let showLines = argv.includes("-l"); +let showBytes = argv.includes("-c"); +let showCharacters = argv.includes("-m"); + +const filePaths = argv.filter((arg) => !arg.startsWith("-")); +// if no flags enable all. +if (!showLines && !showCharacters && !showWords && !showBytes) { + showLines = true; + showCharacters = true; + showWords = true; + showBytes = true; +} + +if (filePaths.length === 0) { + console.error("PLease provide a file path"); + process.exit(1); +} + +let totalLines = 0; +let totalWords = 0; +let totalBytes = 0; +let totalChars = 0; + +filePaths.forEach((filePath) => { + try { + const content = fs.readFileSync(filePath, "utf-8"); + const lineArray = content.split("\n"); + if (content.endsWith("\n")) lineArray.pop(); + const lines = lineArray.length; + + const words = content.trim().split(/\s+/).filter((word) => word != "").length; + const bytes = Buffer.byteLength(content); + const characters = content.length; + + totalLines += lines; + totalWords += words; + totalBytes += bytes; + totalChars += characters; + + let output = ""; + if (showLines) output += lines.toString().padStart(8); + if (showWords) output += words.toString().padStart(8); + if (showBytes) output += bytes.toString().padStart(8); + if (showCharacters) output += characters.toString().padStart(8) + + console.log(`${output} ${filePath}`); + } catch(error) { + console.error(`Error reading ${filePath}: ${error.message}`); + } +}); + +if (filePaths.length > 1) { + let totalOutput = ""; + if (showLines) totalOutput += `${totalLines.toString().padStart(8)}`; + if (showWords) totalOutput += `${totalWords.toString().padStart(8)}`; + if (showBytes) totalOutput += `${totalBytes.toString().padStart(8)}`; + if (showCharacters) totalOutput += `${totalChars.toString().padStart(8)}`; + + console.log(`${totalOutput} total`); +} +