Skip to content

Commit 1a85d7f

Browse files
ebrahimbeiatiDroid-An
authored andcommitted
implements-shell-tool
1 parent b5089a2 commit 1a85d7f

File tree

3 files changed

+199
-0
lines changed

3 files changed

+199
-0
lines changed

implement-shell-tools/cat/cat.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#!/usr/bin/env node
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
//shared line counter across all files(matches cat -n)
6+
let globalLineCounter = 1;
7+
8+
function printFile(filePath, options) {
9+
try {
10+
const content = fs.readFileSync(filePath, 'utf-8');
11+
const lines = content.split('\n');
12+
13+
lines.forEach((line) => {
14+
if(options.numberNonEmpty) {
15+
//-b option: number non-empty lines
16+
if(line.trim()) {
17+
process.stdout.write(
18+
`${String(globalLineCounter).padStart(6)}\t${line}\n`
19+
);
20+
globalLineCounter++;
21+
} else {
22+
process.stdout.write('\n');
23+
}
24+
} else if(options.numberAll) {
25+
//-n option: number all lines
26+
process.stdout.write(
27+
`${String(globalLineCounter).padStart(6)}\t${line}\n`
28+
);
29+
globalLineCounter++;
30+
} else {
31+
//default: just print the line
32+
process.stdout.write(line + '\n');
33+
}
34+
});
35+
36+
} catch (error) {
37+
console.error(`Error reading file ${filePath}: ${error.message}`);
38+
}
39+
}
40+
41+
function main() {
42+
const args = process.argv.slice(2);
43+
const options = {
44+
numberNonEmpty: false,
45+
numberAll: false,
46+
};
47+
const filePatterns = [];
48+
49+
args.forEach((arg) => {
50+
if(arg === '-n') {
51+
options.numberAll = true;
52+
} else if(arg === '-b') {
53+
options.numberNonEmpty = true;
54+
} else {
55+
filePatterns.push(arg);
56+
}
57+
});
58+
// -b takes precedence over -n
59+
if(options.numberNonEmpty) {
60+
options.numberAll = false;
61+
}
62+
63+
if(filePatterns.length === 0) {
64+
console.log("cat: missing file operand");
65+
process.exit(1);
66+
}
67+
68+
const files = filePatterns;
69+
70+
files.forEach((file) => {
71+
const resolvedPath = path.resolve(process.cwd(), file);
72+
printFile(resolvedPath, options);
73+
});
74+
}
75+
76+
main();

implement-shell-tools/ls/ls.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/env node
2+
const fs = require('node:fs');
3+
const path = require('node:path');
4+
5+
function listDirectory(dirPath, showAll, onePerLine) {
6+
try {
7+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
8+
const filtered = entries.filter((entry) => showAll || !entry.name.startsWith('.'));
9+
10+
if(onePerLine) {
11+
filtered.forEach(entry => console.log(entry.name));
12+
} else {
13+
const names = filtered.map(entry => entry.name);
14+
console.log(names.join(' '));
15+
}
16+
} catch (error) {
17+
console.error(`Error reading directory ${dirPath}: ${error.message}`);
18+
}
19+
}
20+
function main() {
21+
const args = process.argv.slice(2);
22+
// Check for options
23+
const showAll = args.includes('-a');
24+
const onePerLine = args.includes('-1');
25+
//remove options from args
26+
const directories = args.filter(arg => arg !== '-a' && arg !== '-1');
27+
28+
// If no directory is specified, list the current directory
29+
if(directories.length === 0) {
30+
listDirectory(process.cwd(), showAll, onePerLine);
31+
return;
32+
}
33+
//If a directory is specified, list that directory
34+
directories.forEach((arg, index) => {
35+
try {
36+
const stats = fs.statSync(arg);
37+
if(stats.isDirectory()) {
38+
//Print header if multiple directories are listed
39+
if(directories.length > 1) console.log(`${arg}:`);
40+
41+
listDirectory(arg, showAll, onePerLine);
42+
//add a blank line between directory listings if there are multiple directories
43+
if(directories.length > 1 && index < directories.length - 1) console.log('');
44+
} else{
45+
console.log(arg);// single file
46+
}
47+
} catch (error) {
48+
console.error(`Error accessing ${arg}: ${error.message}`);
49+
}
50+
});
51+
}
52+
main();

implement-shell-tools/wc/wc.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env node
2+
const fs = require('node:fs');
3+
// Function to count lines, words, and bytes in a file
4+
function countFileContent(content) {
5+
const lines = content.split('\n').length; // Count lines by splitting on newline characters
6+
const words = content.trim().split(/\s+/).filter(Boolean).length; // Split by whitespace and filter out empty strings
7+
const bytes = Buffer.byteLength(content, 'utf8');
8+
return { lines, words, bytes };
9+
}
10+
11+
//print counts in the format of wc according to options
12+
function printCounts(filePath, counts, options) {
13+
const parts = [];
14+
if(options.line) parts.push(counts.lines);
15+
if(options.word) parts.push(counts.words);
16+
if(options.byte) parts.push(counts.bytes);
17+
//if no specific count options are provided, print all counts
18+
if(!options.line && !options.word && !options.byte) {
19+
//default is to print all counts
20+
parts.push(counts.lines, counts.words, counts.bytes);
21+
}
22+
console.log(parts.join('\t'),filePath);
23+
}
24+
25+
function main() {
26+
const args = process.argv.slice(2);
27+
const options = {
28+
line: false,
29+
word: false,
30+
byte: false,
31+
};
32+
33+
//Separate options from file paths
34+
const files = [];
35+
args.forEach((arg) => {
36+
if(arg === '-l') options.line = true;
37+
else if(arg === '-w') options.word = true;
38+
else if(arg === '-c') options.byte = true;
39+
else files.push(arg);
40+
});
41+
42+
if(files.length === 0) {
43+
console.error('No files specified');
44+
process.exit(1);
45+
}
46+
47+
let totalCounts = { lines: 0, words: 0, bytes: 0 };
48+
const multipleFiles = files.length > 1;
49+
50+
files.forEach(file => {
51+
try {
52+
const content = fs.readFileSync(file, 'utf-8');
53+
const counts = countFileContent(content);
54+
55+
// Sum counts for total if multiple files
56+
totalCounts.lines += counts.lines;
57+
totalCounts.words += counts.words;
58+
totalCounts.bytes += counts.bytes;
59+
60+
printCounts(file, counts, options);
61+
} catch (error) {
62+
console.error(`Error reading file ${file}: ${error.message}`);
63+
}
64+
});
65+
66+
// If multiple files, print total counts
67+
if(multipleFiles) {
68+
printCounts('total', totalCounts, options);
69+
}
70+
}
71+
main();

0 commit comments

Comments
 (0)