From 8668211fb8c20db131a4cb85f179a945fdd5bcc3 Mon Sep 17 00:00:00 2001 From: Nataliia Volkova Date: Wed, 19 Nov 2025 12:51:34 +0000 Subject: [PATCH 1/3] 01 Implement shell tools (cat, ls, wc) in JS with mode --- implement-shell-tools/cat/cat.js | 33 +++++++++++++++++++ implement-shell-tools/ls/ls.js | 56 ++++++++++++++++++++++++++++++++ implement-shell-tools/wc/wc.js | 38 ++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 implement-shell-tools/cat/cat.js create mode 100644 implement-shell-tools/ls/ls.js create mode 100644 implement-shell-tools/wc/wc.js diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js new file mode 100644 index 00000000..331be092 --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,33 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; + +const arrArgv = process.argv.slice(2); + +const numberLines = arrArgv.includes("-n"); +const numberNonemptyLines = arrArgv.includes("-b"); + +const nonFlagArrArgv = arrArgv.filter((arr) => !arr.startsWith("-")); + +let number = 1; + +for (let file of nonFlagArrArgv) { + const content = await fs.readFile(file, "utf-8"); + + const linedText = content.split("\n"); + + const numbered = linedText.map((line) => { + if (numberNonemptyLines) { + if (line.trim() === "") { + return line; + } else { + return `${String(number++).padStart(3)} ${line}`; + } + } + if (numberLines) { + return `${String(number++).padStart(3)} ${line}`; + } + + return line; + }); + console.log(numbered.join("\n")); +} diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js new file mode 100644 index 00000000..47414da6 --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,56 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; +import path from "node:path"; + +const arrArgv = process.argv.slice(2); + +const longFormat = arrArgv.includes("-l"); +const showHidden = arrArgv.includes("-a"); + +const paths = arrArgv.filter((argv) => !argv.startsWith("-")); +if (paths.length === 0) path = "[.]"; + +for (let listFile of paths) { + const status = await fs.stat(listFile); + + if (status.isFile()) { + const permissions = (status.mode & 0o777).toString(8); + const sizeFile = status.size; + const owner = status.uid; + const group = status.gid; + const timeMod = status.mtime.toLocaleString(); + + if (longFormat) { + console.log( + `${permissions}, ${owner}, ${group}, ${sizeFile}, ${timeMod}, ${listFile}` + ); + } else { + console.log(listFile); + } + } else { + let files = await fs.readdir(listFile, { withFileTypes: true }); + + if (!showHidden) { + files = files.filter((file) => !file.name.startsWith(".")); + } + + for (let file of files) { + const wholePath = path.join(listFile, file.name); + const statusFile = await fs.stat(wholePath); + + const permissions = (statusFile.mode & 0o777).toString(8); + const sizeFile = statusFile.size; + const owner = statusFile.uid; + const group = statusFile.gid; + const timeMod = statusFile.mtime.toLocaleString(); + + if (longFormat) { + console.log( + `${permissions}, ${owner}, ${group}, ${sizeFile}, ${timeMod}, ${file.name}` + ); + } else { + console.log(file.name); + } + } + } +} diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js new file mode 100644 index 00000000..2648d62d --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,38 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; + +const arrArgv = process.argv.slice(2); + +const lines = arrArgv.includes("-l"); +const words = arrArgv.includes("-w"); +const bytes = arrArgv.includes("-c"); + +const noFlags = !lines && !words && !bytes; + +const paths = arrArgv.filter((argv) => !argv.startsWith("-")); + +for (let path of paths) { + const context = await fs.readFile(path, "utf-8"); + + const countLines = context.split(/\r?\n/).length; + const countWords = context.split(/\s+/).length; + const countBytes = Buffer.byteLength(context, "utf-8"); + + let startInput = ""; + + if (noFlags || lines) { + startInput += `${countLines} `; + } + + if (noFlags || words) { + startInput += `${countWords} `; + } + + if (noFlags || bytes) { + startInput += `${countBytes} `; + } + + startInput += path; + + console.log(startInput); +} From 2f3198f668feeb12e61798a812296e2bf37d6c18 Mon Sep 17 00:00:00 2001 From: Nataliia Volkova Date: Sun, 21 Dec 2025 17:57:22 +0000 Subject: [PATCH 2/3] refactoring Leon suggestion --- implement-shell-tools/cat/cat.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 331be092..0beafdf0 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -15,18 +15,17 @@ for (let file of nonFlagArrArgv) { const linedText = content.split("\n"); + const formatLines = (line) => { + return `${String(number++).padStart(3)} ${line}`; + }; + const numbered = linedText.map((line) => { - if (numberNonemptyLines) { - if (line.trim() === "") { - return line; - } else { - return `${String(number++).padStart(3)} ${line}`; - } + if (numberNonemptyLines && line.trim() === "") { + return line; } - if (numberLines) { - return `${String(number++).padStart(3)} ${line}`; + if (numberNonemptyLines || numberLines) { + return formatLines(line); } - return line; }); console.log(numbered.join("\n")); From 5b61d34b3b2706d2b489da2a7aeca05396ba9c1d Mon Sep 17 00:00:00 2001 From: Nataliia Volkova Date: Sun, 21 Dec 2025 19:33:22 +0000 Subject: [PATCH 3/3] refactoring and debuging --- implement-shell-tools/ls/ls.js | 44 +++++++++++++++------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 47414da6..91060fbb 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -7,23 +7,25 @@ const arrArgv = process.argv.slice(2); const longFormat = arrArgv.includes("-l"); const showHidden = arrArgv.includes("-a"); -const paths = arrArgv.filter((argv) => !argv.startsWith("-")); -if (paths.length === 0) path = "[.]"; - -for (let listFile of paths) { +let paths = arrArgv.filter((argv) => !argv.startsWith("-")); +if (paths.length === 0) paths = ["."]; + +const printWholeList = (stats, name) => { + const permissions = (stats.mode & 0o777).toString(8); + const sizeFile = stats.size; + const owner = stats.uid; + const group = stats.gid; + const timeMod = stats.mtime.toLocaleString(); + + console.log( + `${permissions}, ${owner}, ${group}, ${sizeFile}, ${timeMod}, ${name}` + ); +}; +for (const listFile of paths) { const status = await fs.stat(listFile); - if (status.isFile()) { - const permissions = (status.mode & 0o777).toString(8); - const sizeFile = status.size; - const owner = status.uid; - const group = status.gid; - const timeMod = status.mtime.toLocaleString(); - if (longFormat) { - console.log( - `${permissions}, ${owner}, ${group}, ${sizeFile}, ${timeMod}, ${listFile}` - ); + printWholeList(status, listFile); } else { console.log(listFile); } @@ -34,20 +36,12 @@ for (let listFile of paths) { files = files.filter((file) => !file.name.startsWith(".")); } - for (let file of files) { + for (const file of files) { const wholePath = path.join(listFile, file.name); - const statusFile = await fs.stat(wholePath); - - const permissions = (statusFile.mode & 0o777).toString(8); - const sizeFile = statusFile.size; - const owner = statusFile.uid; - const group = statusFile.gid; - const timeMod = statusFile.mtime.toLocaleString(); if (longFormat) { - console.log( - `${permissions}, ${owner}, ${group}, ${sizeFile}, ${timeMod}, ${file.name}` - ); + const statusFile = await fs.stat(wholePath); + printWholeList(statusFile, file.name); } else { console.log(file.name); }