Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
45 changes: 45 additions & 0 deletions implement-shell-tools/cat/cat.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { program } from "commander";
import {promises as fs} from "node:fs";

program
.name("cat")
.description("read, display, and concatenate text files.")
.option("-n", " Number all output lines.")
.option("-b", " Number non-blank output lines.")
.arguments("<paths...>"); // allow more file paths

program.parse();

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

for(const path of paths){
let content;
try {
content = await fs.readFile(path, "utf-8")
} catch(err) {
console.error(`Error reading file "${path}": ${err.message} `);
continue;
}

// split file into lines
let lines = content.replace(/\n$/, "").split("\n");

let lineNum = 1;

for (const line of lines){
if(options.b){
if(line.trim() !== ""){
console.log(`${lineNum.toString().padStart(5)} ${line}`)
lineNum++;
} else {
console.log("");
}
} else if(options.n){
console.log(`${lineNum.toString().padStart(5)} ${line}`)
lineNum++;
} else{
console.log(`${line}`)
}
}
}
29 changes: 29 additions & 0 deletions implement-shell-tools/ls/ls.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {program} from "commander";
import {promises as fs} from "node:fs";

program
.name("ls")
.description("List all the files in a directory")
.option("-a, --all", "Include hidden files")
.option("-1", "One entry per line")
.argument("[dir]", "directory to list", ".");

program.parse();

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

const entries = await fs.readdir(dir, { withFileTypes: true });

const visibleNames = [];

for(const entry of entries){
if(!options.all && entry.name.startsWith(".")) continue;
visibleNames.push(entry.name);
}

if(options["1"]){
console.log(visibleNames.join("\n"));
} else{
console.log(visibleNames.join(" "));
}
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.0"
}
}
65 changes: 65 additions & 0 deletions implement-shell-tools/wc/wc.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { program } from "commander";
import { promises as fs } from "node:fs";

program
.name("wc")
.description("Display numbers of line, words, and bytes in each file")
.option("-l", "Number of lines")
.option("-w", "Number of words")
.option("-c", "Number of bytes")
.argument("<path...>");

program.parse();

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

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

for(const path of paths){
let content;
try{
content = await fs.readFile(path, "utf-8");
} catch (err){
console.error(`Error reading file "${path}":`, err.message);
continue;
}

const lines = content.replace(/\n$/, "").split("\n");

const words = content.trim().split(/\s+/); // handles multiple spaces
const { size } = await fs.stat(path);

const lineCount = lines.length;
const wordCount = words.length;
const byteCount = size;

totalLines += lineCount;
totalWords += wordCount;
totalBytes += byteCount;

if(options.l) {
console.log(`\t${lineCount} ${path}`);
} else if(options.w) {
console.log(`\t${wordCount} ${path}`);
} else if(options.c) {
console.log(`\t${byteCount} ${path}`)
} else {
console.log(`\t${lineCount}\t${wordCount}\t${size} ${path}`);
}

}

if (paths.length > 1) {
if (options.l) {
console.log(`\t${totalLines} total`);
} else if (options.w) {
console.log(`\t${totalWords} total`);
} else if (options.c) {
console.log(`\t${totalBytes} total`);
} else {
console.log(`\t${totalLines}\t${totalWords}\t${totalBytes} total`);
}
}