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.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {program} from 'commander';
import {promises as fs} from 'node:fs';
import process from 'node:process';

program
.name('cat')
.description('Concatenates and prints the contents of files.')
.argument('<paths...>', 'The paths to the files to concatenate')
.option('-n, --number', 'Number all output lines')
.option('-b, --number-nonblank', 'Number nonempty output lines');

program.parse();

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

if (argv.length < 1) {
console.error(
`Expected at least 1 argument (a path) to be passed but got ${argv.length}.`,
);
process.exit(1);
}

let showLineNumbers = options.number || false;
let showNonEmptyLineNumbers = options.numberNonblank || false;

if (showLineNumbers && showNonEmptyLineNumbers) {
showLineNumbers = false;
}

let lineNumber = 1;
const spacer = ' ';

for (const path of argv) {
const content = await fs.readFile(path, 'utf-8');
const lines = content.split('\n');
while (lines.length > 0 && lines[lines.length - 1] === '') {
lines.pop();
}
for (const line of lines) {
if (showLineNumbers) {
process.stdout.write(`${spacer} ${lineNumber++} ${line}\n`);
} else if (showNonEmptyLineNumbers && line.trim() !== '') {
process.stdout.write(`${spacer} ${lineNumber++} ${line}\n`);
} else {
process.stdout.write(`${line}\n`);
}
}
}
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.

15 changes: 15 additions & 0 deletions implement-shell-tools/cat/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "cat",
"version": "1.0.0",
"description": "You should already be familiar with the `cat` command line tool.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"commander": "^14.0.3"
}
}
35 changes: 35 additions & 0 deletions implement-shell-tools/ls/ls.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { program } from 'commander';
import process from 'node:process';
import { promises as fs } from 'node:fs';

program
.name('ls')
.description('Lists the contents of a directory.')
.argument('[path]', 'The path to the directory to list, defaults to the current directory')
.option('-a, --all', 'Do not ignore entries starting with .')
.option('-1', 'List one file per line');

program.parse();

const argv = program.args;
const path = argv[0] || '.';

let showAll = program.opts().all || false;
let onePerLine = program.opts()['1'] || false;

try {
const files = await fs.readdir(path);
files.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }));
for (const file of files) {
if (showAll || !file.startsWith('.')) {
if (onePerLine) {
process.stdout.write(`${file}\n`);
} else {
process.stdout.write(`${file} `);
}
}
}
} catch (err) {
process.stderr.write(`cannot access '${path}': No such file or directory\n`);
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.

15 changes: 15 additions & 0 deletions implement-shell-tools/ls/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "ls",
"version": "1.0.0",
"description": "You should already be familiar with the `ls` command line tool.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"commander": "^14.0.3"
}
}
26 changes: 26 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.mjs",
"type": "module",
"dependencies": {
"commander": "^14.0.3"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
34 changes: 34 additions & 0 deletions implement-shell-tools/wc/wc.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { program } from 'commander';
import process from 'node:process';
import { promises as fs } from 'node:fs';

program
.name('wc')
.description('Counts the number of lines, words, and characters in a file.')
.argument('<path>', 'The path to the file to analyze')
.option('-l, --lines', 'Only count lines')
.option('-w, --words', 'Only count words')
.option('-c, --characters', 'Only count characters');

program.parse();

const argv = program.args;

if (argv.length != 1) {
console.error(
`Expected exactly 1 argument (a path) to be passed but got ${argv.length}.`);
process.exit(1);
}
const path = argv[0];
const options = program.opts();

let showLines = options.lines || (!options.words && !options.characters);
let showWords = options.words || (!options.lines && !options.characters);
let showCharacters = options.characters || (!options.lines && !options.words);

const content = await fs.readFile(path, 'utf-8');

const lineCount = content.split('\n').filter(Boolean).length;
const wordCount = content.split(' ').filter(Boolean).length;
const characterCount = content.length;
console.log(` ${showLines ? lineCount : ''} ${showWords ? wordCount : ''} ${showCharacters ? characterCount : ''} ${path}`);
Loading