Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions implement-shell-tools/cat/cat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { program } from "commander";
import { promises as fs } from "node:fs";

program
.name("cat command")
.description("create cat command")
.option("-n", "Number all lines")
.option("-b", "Number non-empty lines")
.argument("<paths...>", "File paths");

program.parse();
const paths = program.args;
const number = program.opts().n;
const nonEmptyLine = program.opts().b;

let lineNumber = 1;

for (const path of paths) {
try {
const read = await fs.readFile(path, "utf-8");
const lines = read.split("\n");

function printNumLine(line) {
console.log(`${String(lineNumber).padStart(6, " ")} ${line}`);
lineNumber++;
}

for (let i of lines) {
if (number || (nonEmptyLine && i.trim() !== "")) {
printNumLine(i);
} else {
console.log(i);
}
}
} catch (err) {
console.error(`File could not read: ${path}`);
}
}
43 changes: 43 additions & 0 deletions implement-shell-tools/ls/ls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { program } from "commander";
import { promises as fs } from "node:fs";

program
.name("ls command")
.description("create ls command")
.option("-1", "One entry per line")
.option("-a", "Show all files including hidden")
.argument("[paths...]", "File paths");

program.parse();

const opts = program.opts();
const paths = program.args.length > 0 ? program.args : ["."];
const onePerLine = opts["1"];
const showAll = opts.a;

for (const targetPath of paths) {
try {
let files = await fs.readdir(targetPath);

if (!showAll) {
files = files.filter((f) => !f.startsWith("."));
}


if (paths.length > 1) {
console.log(`${targetPath}:`);
}

if (onePerLine) {
for (const f of files) console.log(f);
} else {
console.log(files.join(" "));
}

if (paths.length > 1) {
console.log();
}
} catch (err) {
console.error(`ls: cannot access '${targetPath}': ${err.message}`);
}
}
25 changes: 25 additions & 0 deletions implement-shell-tools/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions implement-shell-tools/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "implement-shell-tools",
"version": "1.0.0",
"description": "Your task is to re-implement shell tools you have used.",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"commander": "^14.0.2"
}
}
54 changes: 54 additions & 0 deletions implement-shell-tools/wc/wc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { program } from "commander";
import { promises as fs } from "node:fs";

program
.option("-l", "Print only the line count")
.option("-w", "Print only the word count")
.option("-c", "Print only the byte count")
.argument("<paths...>", "One or more file paths");

program.parse();

const opts = program.opts();
const paths = program.args;

async function wcFile(path) {
const content = await fs.readFile(path, "utf8");

const lines = content.split("\n").length;
const words = content.trim().split(/\s+/).filter(Boolean).length;
const bytes = Buffer.byteLength(content, "utf8");

return { lines, words, bytes };
}

function formatOutput(counts, filename, opts) {
if (opts.l) return `${counts.lines} ${filename}`;
if (opts.w) return `${counts.words} ${filename}`;
if (opts.c) return `${counts.bytes} ${filename}`;

return `${String(counts.lines).padStart(8)} ${String(counts.words).padStart(
8
)} ${String(counts.bytes).padStart(8)} ${filename}`;
}

async function main() {
let total = { lines: 0, words: 0, bytes: 0 };
let multipleFiles = paths.length > 1;

for (const path of paths) {
const counts = await wcFile(path);

total.lines += counts.lines;
total.words += counts.words;
total.bytes += counts.bytes;

console.log(formatOutput(counts, path, opts));
}

if (multipleFiles) {
console.log(formatOutput(total, "total", opts));
}
}

main();