-
-
Notifications
You must be signed in to change notification settings - Fork 17
London | Ameneh Keshavarz | Implement-shell-tools| WEEK3 #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b841fb7
8ec0407
8562ec4
1e51d9b
ad139f6
00bceff
ddc34e2
36817a0
6e9c662
7416d4e
4c422ff
f79d6fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
const { promises: fs } = require("fs"); | ||
const { program } = require("commander"); | ||
|
||
program | ||
.name("cat") | ||
.description("Implement a version of the cat program") | ||
.option("-n, --number", "Number all output lines, starting at 1") | ||
.option("-b, --number2", "Number non-empty output lines, starting at 1") | ||
.argument("<paths...>", "The file paths to process") | ||
.parse(); | ||
|
||
const { number: nOption, number2: bOption } = program.opts(); | ||
const paths = program.args; | ||
|
||
let lineNumber = 1; | ||
let nonEmptyLineNumber = 1; | ||
|
||
function printLinesWithOptions(lines) { | ||
lines.forEach(line => { | ||
if (nOption) { | ||
console.log(`${String(lineNumber++).padStart(6)} ${line}`); | ||
} else if (bOption && line.trim()) { | ||
console.log(`${String(nonEmptyLineNumber++).padStart(6)} ${line}`); | ||
} else { | ||
console.log(line); | ||
} | ||
}); | ||
} | ||
|
||
async function readFileContent(path) { | ||
try { | ||
const content = await fs.readFile(path, "utf-8"); | ||
const lines = content.split("\n"); | ||
printLinesWithOptions(lines); | ||
} catch (err) { | ||
console.error(`Error reading file ${path}: ${err.message}`); | ||
} | ||
} | ||
|
||
Promise.all(paths.map(readFileContent)); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
const fs = require('fs'); | ||
const { program } = require('commander'); | ||
|
||
program | ||
.option('-a, --all', 'Show hidden files') | ||
.option('-1', 'Show one file per line') | ||
.argument('[dirPaths...]', 'Directory paths', ['.']) // Support multiple directories | ||
.parse(process.argv); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens when we receive more than one argument? (e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, I removed the unnecessary special case for single input and added support for multiple directory arguments like node ls.js dir1 dir2. I also made sure the code handles each path safely and gives clear output. |
||
|
||
const { all, '1': onePerLine } = program.opts(); | ||
const dirPaths = program.args; | ||
|
||
function listDirectoryContents(dirPath, showHidden = false, onePerLine = false) { | ||
fs.readdir(dirPath, (err, files) => { | ||
if (err) { | ||
console.error(`Error reading directory '${dirPath}': ${err.message}`); | ||
return; | ||
} | ||
|
||
if (!showHidden) { | ||
files = files.filter(file => !file.startsWith('.')); | ||
} | ||
|
||
console.log(`\n${dirPath}:`); | ||
if (onePerLine) { | ||
files.forEach(file => console.log(file)); | ||
} else { | ||
console.log(files.join(' ')); | ||
} | ||
}); | ||
} | ||
|
||
dirPaths.forEach(dirPath => { | ||
if (typeof dirPath !== 'string') { | ||
console.error(`Error: Invalid directory path '${dirPath}'`); | ||
return; | ||
} | ||
listDirectoryContents(dirPath, all, onePerLine); | ||
}); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"type": "commonjs", | ||
"dependencies": { | ||
"commander": "^11.0.0" | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
const { promises: fs } = require('fs'); | ||
const path = require('path'); | ||
const { program } = require('commander'); | ||
|
||
program | ||
.description('Count lines, words, and characters in the specified files') | ||
.option('-l, --lines', 'Count the lines') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When counting lines, your program counts one more than ➜ wc -l sample-files/3.txt
5 sample-files/3.txt
➜ node wc.js -l sample-files/3.txt
6 /Users/blorente/code/github.com/CodeYourFuture/Module-Tools/implement-shell-tools/wc/sample-files/3.txt Why does this happen? How could we fix it so that we print the right number of lines? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was using data.split('\n').length, which overcounts lines. To match the behavior of wc -l, I updated it to: |
||
.option('-w, --words', 'Count the words') | ||
.option('-c, --characters', 'Count the characters') | ||
.parse(process.argv); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your solution prints the full path of each file: ➜ node wc.js -l sample-files/3.txt
6 /Users/blorente/code/github.com/CodeYourFuture/Module-Tools/implement-shell-tools/wc/sample-files/3.txt Whereas ➜ wc -l sample-files/3.txt
5 sample-files/3.txt How would you modify this code to print the relative path? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was printing the absolute path using path.resolve, which made the output differ from wc. I’ve updated the code to print the original file argument instead, so it now shows the relative path the we type. |
||
|
||
const options = program.opts(); | ||
const files = program.args; | ||
|
||
if (files.length === 0) { | ||
console.error("Error: No files provided."); | ||
process.exit(1); | ||
} | ||
|
||
async function countFileStats(filePath, options) { | ||
try { | ||
const data = await fs.readFile(filePath, 'utf8'); | ||
|
||
const lines = (data.match(/\n/g) || []).length; | ||
const words = data.split(/\s+/).filter(Boolean).length; | ||
const characters = data.length; | ||
|
||
const result = { lines, words, characters }; | ||
const output = []; | ||
if (options.lines) output.push(result.lines); | ||
if (options.words) output.push(result.words); | ||
if (options.characters) output.push(result.characters); | ||
if (output.length === 0) output.push(result.lines, result.words, result.characters); | ||
|
||
return { file: filePath, output: output.join(' '), lines, words, characters }; | ||
} catch (err) { | ||
console.error(`Error reading file: ${filePath}`); | ||
return null; | ||
} | ||
} | ||
|
||
async function processFiles() { | ||
let totalLines = 0; | ||
let totalWords = 0; | ||
let totalCharacters = 0; | ||
|
||
for (const file of files) { | ||
const filePath = path.resolve(file); | ||
const result = await countFileStats(filePath, options); | ||
|
||
if (result) { | ||
console.log(result.output, file); | ||
totalLines += result.lines; | ||
totalWords += result.words; | ||
totalCharacters += result.characters; | ||
} | ||
} | ||
|
||
if (files.length > 1) { | ||
const totals = []; | ||
if (options.lines) totals.push(totalLines); | ||
if (options.words) totals.push(totalWords); | ||
if (options.characters !== false) totals.push(totalCharacters); | ||
|
||
if (totals.length > 0) { | ||
console.log(totals.join(' ') + ' total'); | ||
} | ||
} | ||
} | ||
|
||
processFiles(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
-a
is set, it should also print the current directory (.
) and the parent diractory (..
).➜ ls -1 -a sample-files . .. .hidden.txt 1.txt 2.txt 3.txt dir
How could we modify this solution so that we do print them?