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

const argv = process.argv.slice(2);

const dash = argv.filter(arg => arg.startsWith('-'));
const filePaths = argv.filter(arg => !arg.startsWith('-'));

const showLineNumbers = dash.includes('-n');
const showNonBlank = dash.includes('-b');

let lineCounter = 1;

for (const filePath of filePaths) {
let content;
try {
content = await fs.readFile(filePath, 'utf8');
} catch {
console.error(`cat: ${filePath}: No file or directory exists`);
process.exit(1);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will stop processing of other files. Real cat continues processing of other files.

}

const lines = content.split('\n');

if (lines[lines.length - 1] === '') lines.pop();

for (const line of lines) {
const isBlank = line.trim() === '';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

real cat treats lines with spaces as real lines and does not ignore them


if (showNonBlank) {
if (isBlank) {
console.log('');
} else {
console.log(`${String(lineCounter).padStart(6)}\t${line}`);
lineCounter++;
}
} else if (showLineNumbers) {
console.log(`${String(lineCounter).padStart(6)}\t${line}`);
lineCounter++;
} else {
console.log(line);
}
}
}
19 changes: 19 additions & 0 deletions implement-shell-tools/ls/lsFile.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import process from "node:process";
import { promises as fs } from "node:fs";

const argv = process.argv.slice(2);

const dash = argv.filter(arg => arg.startsWith('-'));
const paths = argv.filter(arg => !arg.startsWith('-'));

const showAll = dash.includes('-a');

const targetDir = paths[0] ?? '.';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we have multiple paths?


const entries = await fs.readdir(targetDir);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if no dir is found?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entries is not sorted. readdir order is filesystem-dependent. Sort before output: entries.sort(). The . and .. entries should remain first.


const result = showAll ? ['.', '..', ...entries] : entries.filter(e => !e.startsWith('.'));

for (const entry of result) {
console.log(entry);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real ls default output is space-separated on one line; one-per-line requires the -1 flag. This always uses one-per-line regardless. The -1 flag needs to be implemented and the default output should join entries with spaces (plus a trailing newline).

}
55 changes: 55 additions & 0 deletions implement-shell-tools/wc/wcFile.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import process from "node:process";
import { promises as fs } from "node:fs";

const argv = process.argv.slice(2);

const dash = argv.filter(arg => arg.startsWith('-'));
const filePaths = argv.filter(arg => !arg.startsWith('-'));

const forLines = dash.includes('-l');
const forWords = dash.includes('-w');
const forBytes = dash.includes('-c');

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

for (const filePath of filePaths) {
let content;
try {
content = await fs.readFile(filePath, 'utf8');
} catch {
console.error(`wc: ${filePath}: No file or directory exists`);
process.exit(1);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same situation: if one file is problematic, the whole execution stops. Real wc continues processing of other files.

}

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

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

if (forLines) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if we have several flags simultaneously?

console.log(`${String(lines).padStart(8)} ${filePath}`);
} else if (forWords) {
console.log(`${String(words).padStart(8)} ${filePath}`);
} else if (forBytes) {
console.log(`${String(bytes).padStart(8)} ${filePath}`);
} else {
console.log(`${String(lines).padStart(8)} ${String(words).padStart(8)} ${String(bytes).padStart(8)} ${filePath}`);
}
}

if (filePaths.length > 1) {
if (forLines) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we have several flags passed?

console.log(`${String(totalLines).padStart(8)} total`);
} else if (forWords) {
console.log(`${String(totalWords).padStart(8)} total`);
} else if (forBytes) {
console.log(`${String(totalBytes).padStart(8)} total`);
} else {
console.log(`${String(totalLines).padStart(8)} ${String(totalWords).padStart(8)} ${String(totalBytes).padStart(8)} total`);
}
}
Loading