diff --git a/implement-shell-tools/cat/cat.mjs b/implement-shell-tools/cat/cat.mjs new file mode 100644 index 000000000..b8ffa4d7b --- /dev/null +++ b/implement-shell-tools/cat/cat.mjs @@ -0,0 +1,47 @@ +import { program } from "commander"; +import{promises as fs} from "node:fs"; + + +program +.name("cat") +.description("displays the contents of a file") +.option("-n, --number", "Number all output lines") +.option("-b, --number-nonblank", "Number non-blank output lines only") +.argument(""); + +program.parse(); + + +const args = program.args; +const opts = program.opts(); + +if (args.length === 0) { + console.error("Error: Missing argument."); + program.help(); +} + +let globalLineNumber = 1; + +for (const path of args) { + try { + const content = await fs.readFile(path, "utf-8"); + const lines = content.split('\n'); + + if (opts.number) { + lines.forEach((line, idx) => { + console.log(`${idx + 1}\t${line}`); + }); + } else if (opts.numberNonblank) { + for (const line of lines) { + if (line.trim() !== '') { + console.log(`${globalLineNumber}\t${line}`); + globalLineNumber++; + } + } + } else { + console.log(content); + } + } catch (err) { + console.error(`Error reading file "${path}": ${err.message}`); + } +} \ No newline at end of file diff --git a/implement-shell-tools/ls/ls.mjs b/implement-shell-tools/ls/ls.mjs new file mode 100644 index 000000000..04f34eb65 --- /dev/null +++ b/implement-shell-tools/ls/ls.mjs @@ -0,0 +1,33 @@ +import {program} from "commander"; +import {promises as fs} from "node:fs"; + +program +.name("ls") +.description("displays files in a directory") +.option("-1, --one", "displays each file in its own line") +.option("-a, --all", "displays all files including hidden files") +.arguments("") + +await program.parseAsync(); + +const opts = program.opts(); +const args = program.args; + +if (args.length === 0) { + console.error("Error: Missing argument."); + program.help(); +} + +const path = args[0]; +const files = await fs.readdir(path); + +let visibleFiles = files; +if (!opts.all) { + visibleFiles = files.filter(file => !file.startsWith(".")); +} + +if (opts.one) { + visibleFiles.forEach(console.log); +} else { + console.log(visibleFiles.join(" ")); +} \ No newline at end of file diff --git a/implement-shell-tools/wc/wc.mjs b/implement-shell-tools/wc/wc.mjs new file mode 100644 index 000000000..b6df2e47b --- /dev/null +++ b/implement-shell-tools/wc/wc.mjs @@ -0,0 +1,72 @@ +import {program} from "commander"; +import{promises as fs} from "node:fs"; + +program +.name("wc") +.description("counts lines, words, and bytes") +.option("-l, --line", "counts number of lines in the file") +.option("-w, --words", "counts number of words in the file") +.option("-c, --bytes", "counts number of bytes in the file") +.argument("") + +program.parse(); + +const args= program.args; +const opts = program.opts(); + +if(args.length === 0){ + console.error("Error: Missing argument."); + program.help(); +} + +const countLines = content => content.split(/\r?\n/).length; +const countWords = content => content.trim().split(/\s+/).filter(Boolean).length; +const countBytes = content => Buffer.byteLength(content, "utf-8"); + +// store totals for multiple files +let totalLines = 0; +let totalWords = 0; +let totalBytes = 0; + +for (const path of args) { + try { + const content = await fs.readFile(path, "utf-8"); + + const lines = countLines(content); + const words = countWords(content); + const bytes = countBytes(content); + + totalLines += lines; + totalWords += words; + totalBytes += bytes; + + // collect counts based on options + const output = []; + if (opts.line) output.push(lines); + if (opts.words) output.push(words); + if (opts.bytes) output.push(bytes); + + // if no options are passed, print all + if (!opts.line && !opts.words && !opts.bytes) { + output.push(lines, words, bytes); + } + + console.log(...output, path); + } catch (err) { + console.error(`Error reading file "${path}": ${err.message}`); + } +} + +// print totals if more than one file +if (args.length > 1) { + const totalOutput = []; + if (opts.line) totalOutput.push(totalLines); + if (opts.words) totalOutput.push(totalWords); + if (opts.bytes) totalOutput.push(totalBytes); + + if (!opts.line && !opts.words && !opts.bytes) { + totalOutput.push(totalLines, totalWords, totalBytes); + } + + console.log(...totalOutput, "total"); +} \ No newline at end of file diff --git a/individual-shell-tools/ls/script-01.sh b/individual-shell-tools/ls/script-01.sh index 241b62f5e..081f2c7c2 100755 --- a/individual-shell-tools/ls/script-01.sh +++ b/individual-shell-tools/ls/script-01.sh @@ -13,3 +13,4 @@ fi # TODO: Write a command to list the files and folders in this directory. # The output should be a list of names including child-directory, script-01.sh, script-02.sh, and more. +ls \ No newline at end of file diff --git a/individual-shell-tools/ls/script-02.sh b/individual-shell-tools/ls/script-02.sh index d0a5a10f4..48c16842c 100755 --- a/individual-shell-tools/ls/script-02.sh +++ b/individual-shell-tools/ls/script-02.sh @@ -4,3 +4,4 @@ set -euo pipefail # TODO: Write a command which lists all of the files in the directory named child-directory. # The output should be a list of names: helper-1.txt, helper-2.txt, helper-3.txt. +ls chile \ No newline at end of file