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
49 changes: 49 additions & 0 deletions implement-shell-tools/cat/cat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import process from "node:process";
import { promises as fs } from "node:fs";
import { program } from "commander";

program
.name("cat")
.description("Concatenate and print files")
.option("-n, --number", "Number all lines", false)
.option("-b, --number-nonblank", "Number non-empty lines", false)
.argument("<path...>", "The file(s) to read");

program.parse();

const paths = program.args;
if (paths.length === 0) {
console.error("Please provide at least one file");
process.exit(1);
}

const options = program.opts();
const showLineNumbers = options.number;
const numberNonEmpty = options.numberNonblank;

let lineNumber = 1;

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

for (const line of lines) {
if (numberNonEmpty) {
if (line.trim() !== "") {
console.log(`${lineNumber} ${line}`);
lineNumber++;
} else {
console.log("");
}
} else if (showLineNumbers) {
console.log(`${lineNumber} ${line}`);
lineNumber++;
} else {
console.log(line);
}
}
} catch (err) {
console.error(`Error reading file: ${path}`);
}
}
25 changes: 25 additions & 0 deletions implement-shell-tools/cat/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/cat/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "cat",
"version": "1.0.0",
"description": "You should already be familiar with the `cat` command line tool.",
"main": "cat.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"commander": "^14.0.3"
}
}
40 changes: 40 additions & 0 deletions implement-shell-tools/ls/ls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import process from "node:process";
import { promises as fs } from "node:fs";
import { program } from "commander";

program
.name("ls")
.description("List directory contents")
.option("-1", "List one file per line")
.option("-a, --all", "Include hidden files", false)
.argument("[path]", "Directory path", ".");

program.parse();

const path = program.args[0] || ".";
const options = program.opts();

const showAll = options.all;

try {
const stat = await fs.stat(path);

if (stat.isDirectory()) {
const files = await fs.readdir(path);

let filteredFiles = files;

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

for (const file of filteredFiles) {
console.log(file);
}
} else {
console.log(path);
}
} catch (err) {
console.error(`Error: cannot access ${path}`);
process.exit(1);
}
25 changes: 25 additions & 0 deletions implement-shell-tools/ls/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/ls/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "ls",
"version": "1.0.0",
"description": "You should already be familiar with the `ls` command line tool.",
"main": "ls.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"commander": "^14.0.3"
}
}
25 changes: 25 additions & 0 deletions implement-shell-tools/wc/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/wc/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "wc",
"version": "1.0.0",
"description": "You should already be familiar with the `wc` command line tool.",
"main": "wc.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"commander": "^14.0.3"
}
}
60 changes: 60 additions & 0 deletions implement-shell-tools/wc/wc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import process from "node:process";
import { promises as fs } from "node:fs";
import { program } from "commander";

program
.name("wc")
.description("Word, line, and byte count")
.option("-l, --lines", "Count lines")
.option("-w, --words", "Count words")
.option("-c, --bytes", "Count bytes")
.argument("<paths...", "File to process");

program.parse();

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

if (paths.length === 0) {
console.error("Please provide at least one file.");
process.exit(1);
}

let totalLines = 0;
let totalWords = 0;
let totalBytes = 0;

for (const path of paths) {
try {
const content = await fs.readFile(path, "utf-8");

const lines = content.split("\n").length - 1;
const words =
content.trim() === "" ? 0 : content.trim().split(/\s+/).length;
const bytes = Buffer.byteLength(content, "utf-8");

totalLines += lines;
totalWords += words;
totalBytes += bytes;

printResult(lines, words, bytes, path, options);
} catch (err) {
console.error(`Error reading file: ${path}`);
}
}

if (paths.length > 1) {
printResult(totalLines, totalWords, totalBytes, "total", options);
}

function printResult(lines, words, bytes, label, options) {
if (options.lines) {
console.log(`${lines} ${label}`);
} else if (options.words) {
console.log(`${words} ${label}`);
} else if (options.bytes) {
console.log(`${bytes} ${label}`);
} else {
console.log(`${lines} ${words} ${bytes} ${label}`);
}
}