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
40 changes: 40 additions & 0 deletions implement-shell-tools/cat/cat.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";

// THis will give an array without the path to node and to the file.
const argv = process.argv.slice(2);

//Get line numbers.
const showNumbers = argv.includes("-n");
const showNonBlankNumbers = argv.includes("-b");

//filter the - from the array argv as it's a flag.
const filePaths = argv.filter((arg) => !arg.startsWith("-"));
let counterLines = 1;

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

//split the text at the new line character.
const splitLines = content.split("\n");

splitLines.forEach((line) => {
if (showNumbers) {
console.log(`${counterLines++} ${line}`);
} else if (showNonBlankNumbers) {
// increment and show numbers only if the line is not empty.
if (line.trim() !== "") {
console.log(`${counterLines++} ${line}`);
} else {
// print empty lines
console.log(line);
}
} else {
console.log(line);
}
});
} catch (error) {
console.log(`Could not read: ${path}`);
}
}
28 changes: 28 additions & 0 deletions implement-shell-tools/ls/ls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import fs from "node:fs";
import process from "node:process";

// This will give an array without the path to node and to the file.
const argv = process.argv.slice(2);

// filter the flag to find the target folder.
const filePaths = argv.filter((arg) => !arg.startsWith("-"));
const showHiddenFiles = argv.includes("-a");

// if no folder provide we use the current one
const target = filePaths[0] || ".";
// read the file.
const files = fs.readdirSync(target);

// save the result into the variable.
let filteredFIles = files;
if (!showHiddenFiles) {
filteredFIles = files.filter((file) => !file.startsWith("."));
} else {
// we use spread operator to merge the paths.
filteredFIles = [".", "..", ...files];
}

// Print using -1 .
filteredFIles.forEach((file) => {
console.log(file);
});
40 changes: 40 additions & 0 deletions implement-shell-tools/wc/wc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import process, { exit } from "node:process";
import fs from "node:fs";

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

const showWords = argv.includes("-w");
const showLines = argv.includes("-l");
const showBytes = argv.includes("-c");
const showCharacters = argv.includes("-m");

// filter flags, and getting the string of filename
const filePaths = argv.filter((arg) => !arg.startsWith("-"));

const noFlags = !showLines && !showCharacters && !showWords && !showCharacters;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The variable 'noFlags' is intended to check if no flags are set, but the logic includes '!showCharacters' twice and omits '!showBytes'. This could be confusing to someone reading the code. How could you make the naming and logic clearer so that it accurately reflects the intent and is easy to understand?

if (!filePaths) {
console.error("PLease provide a file path");
process.exit(1);
}
// loop trough the array to get each file path.
filePaths.forEach((filePath) => {
const content = fs.readFileSync(filePath, "utf-8");

const lines = content.split("\n").length - 1;
const words = content
.trim()
.split(/\s+/)
.filter((word) => word != "").length;
// here I used Buffer.byteLength even if characters and bytes can be the same number .length, however sometimes an emoji or special characters can be heavier 2b or 4b
const bytes = Buffer.byteLength(content);
const characters = content.length;

let output = "";

if (showLines || noFlags) output += `${lines} `;
if (showWords || noFlags) output += `${words} `;
if (showBytes || noFlags) output += `${bytes} `;
if (showCharacters || noFlags) output += `${characters} `;
Comment on lines +32 to +37
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You assign the result of fs.readFileSync(filePath, "utf-8") to 'content', and then use it immediately for processing. Since you use 'content' multiple times, this seems reasonable. However, for the 'output' variable, you build up a string by appending to it in several if statements. Do you think there is a clearer way to construct the output string, perhaps by collecting the values in an array and joining them, to avoid the need for a mutable variable?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@Droid-An This comment seems quite odd?

The "content"-related stuff feels irrelevant. And I'm not sure accumulating in an array is any cleaner than mutating a string? There may be other benefits (e.g. avoiding O(n^2) copies repeatedly appending), but avoiding a mutable variable by using something that happens to be internally mutable because it's a reference type seems like an odd suggestion?


console.log(`${output} ${filePath}`);
});
2 changes: 1 addition & 1 deletion individual-shell-tools/sed/script-01.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ set -euo pipefail

# TODO: Write a command to output input.txt with all occurrences of the letter `i` replaced with `I`.
# The output should contain 11 lines.
# The first line of the output should be: "ThIs Is a sample fIle for experImentIng with sed.".
# The first line of the output should be: "ThIs Is a sample fIle for experImentIng wIth sed.".
Loading