From 276fc2be1d76d7ee93ca1a78f2f3d80722ee4542 Mon Sep 17 00:00:00 2001 From: Jamal Laqdiem Date: Sat, 21 Mar 2026 08:46:45 +0000 Subject: [PATCH 1/3] implementing a logic that behive as cat command --- implement-shell-tools/cat/cat.js | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 implement-shell-tools/cat/cat.js diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js new file mode 100644 index 000000000..7c88bd963 --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,40 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; + +// THis will give an array without the path to node and to the file. +const argv = process.argv.slice(2); + +//Get line numbers. +const showNumbers = argv.includes("-n"); +const showNonBlankNumbers = argv.includes("-b"); + +//filter the - from the array argv as it's a flag. +const filePaths = argv.filter((arg) => !arg.startsWith("-")); +let counterLines = 1; + +for (const path of filePaths) { + try { + const content = await fs.readFile(path, "utf-8"); + + //split the text at the new line character. + const splitLines = content.split("\n"); + + splitLines.forEach((line) => { + if (showNumbers) { + console.log(`${counterLines++} ${line}`); + } else if (showNonBlankNumbers) { + // increment and show numbers only if the line is not empty. + if (line.trim() !== "") { + console.log(`${counterLines++} ${line}`); + } else { + // print empty lines + console.log(line); + } + } else { + console.log(line); + } + }); + } catch (error) { + console.log(`Could not read: ${path}`); + } +} From 8675a8b2fca34151e3d2c70721e021bdb15e9417 Mon Sep 17 00:00:00 2001 From: Jamal Laqdiem Date: Tue, 24 Mar 2026 14:24:42 +0000 Subject: [PATCH 2/3] Solving The exercise for ls command. --- implement-shell-tools/ls/ls.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 implement-shell-tools/ls/ls.js diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js new file mode 100644 index 000000000..18b2116e0 --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,28 @@ +import fs from "node:fs"; +import process from "node:process"; + +// This will give an array without the path to node and to the file. +const argv = process.argv.slice(2); + +// filter the flag to find the target folder. +const filePaths = argv.filter((arg) => !arg.startsWith("-")); +const showHiddenFiles = argv.includes("-a"); + +// if no folder provide we use the current one +const target = filePaths[0] || "."; +// read the file. +const files = fs.readdirSync(target); + +// save the result into the variable. +let filteredFIles = files; +if (!showHiddenFiles) { + filteredFIles = files.filter((file) => !file.startsWith(".")); +} else { + // we use spread operator to merge the paths. + filteredFIles = [".", "..", ...files]; +} + +// Print using -1 . +filteredFIles.forEach((file) => { + console.log(file); +}); From 99cb233b094f5a4c53bbdeaec48c7964a09e2570 Mon Sep 17 00:00:00 2001 From: Jamal Laqdiem Date: Thu, 26 Mar 2026 11:00:56 +0000 Subject: [PATCH 3/3] feat: create a script that behave like wc command. --- implement-shell-tools/wc/wc.js | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 implement-shell-tools/wc/wc.js diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js new file mode 100644 index 000000000..2860444ae --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,40 @@ +import process, { exit } from "node:process"; +import fs from "node:fs"; + +const argv = process.argv.slice(2); + +const showWords = argv.includes("-w"); +const showLines = argv.includes("-l"); +const showBytes = argv.includes("-c"); +const showCharacters = argv.includes("-m"); + +// filter flags, and getting the string of filename +const filePaths = argv.filter((arg) => !arg.startsWith("-")); + +const noFlags = !showLines && !showCharacters && !showWords && !showCharacters; +if (!filePaths) { + console.error("PLease provide a file path"); + process.exit(1); +} +// loop trough the array to get each file path. +filePaths.forEach((filePath) => { + const content = fs.readFileSync(filePath, "utf-8"); + + const lines = content.split("\n").length - 1; + const words = content + .trim() + .split(/\s+/) + .filter((word) => word != "").length; + // here I used Buffer.byteLength even if characters and bytes can be the same number .length, however sometimes an emoji or special characters can be heavier 2b or 4b + const bytes = Buffer.byteLength(content); + const characters = content.length; + + let output = ""; + + if (showLines || noFlags) output += `${lines} `; + if (showWords || noFlags) output += `${words} `; + if (showBytes || noFlags) output += `${bytes} `; + if (showCharacters || noFlags) output += `${characters} `; + + console.log(`${output} ${filePath}`); +});