how to use grep command programmatically in node.js - javascript

I am trying to Display only the vmRSS Attribute. When I run the command command
cat ./Status
I get alot of attributes and their corresponding values. What I am trying to do is to Display only the vmRSS programmatically. I can do it in the console as follows:
cat ./status | grep VmR
but how can I do it programmatically.
my attempts
const ls2 = spawn('cat', ['/proc/' + process.pid + '/status']);

Since child_process spawn launch a shell in a subprocess, I think you're better to do that within the current shell instead, with child_process exec() command.
Here is an example (thanks to #Inian):
const { exec } = require('child_process');
exec('grep VmR /proc/' + process.pid + '/status', (err, stdout) => {
if (err) return console.log(err)
console.log(stdout) // VmRSS: 13408 kB
})
Otherwise, if you don't want to spawn a shell to get that info, you could use fs to read the file, something like that:
const fs = require('fs');
let process_status = '/proc/' + process.pid + '/status';
fs.readFile(process_status, { encoding: 'utf8' }, (err, buf) => {
if (err) return console.log(err)
let lines = buf.split('\n') // each line in an array
let line = lines.filter(line => /VmRSS/.test(line)) // find interesting line
let VmR = line[0].replace(/\t/g, '') // clean output removing tabulation
console.log(VmR) // VmRSS: 13208 kB
})

Related

Deleting a line in a txt file with Node.js

I recently made a script in which I want to delete an EXACT match from a txt file with node. It print's out true but doesn't actually remove the line from the txt file. I am using discord to get the argument.
I'm not sure what I'm doing wrong but here is my script:
const fs = require('fs')
fs.readFile('notredeemed.txt', function (err, data) {
if (err) throw err;
if (data.toString().match(new RegExp(`^${args[0]}$`, "m"))) {
fs.readFile('notredeemed.txt', 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
var result = data.replace(/${args[0]/g, '');
fs.writeFile('notredeemed.txt', result, 'utf8', function (err) {
if (err) return console.log(err);
});
});
console.log("true")
If someone could help me I would appreciate it :)
I think you can do it very similarly as your current solution, just the regex is a little off.
Instead of just using ^ and $ to indicate that the entire string starts and ends with the args[0], I used two capture groups as the delimiters of a line.
This one matches any newline character or the beginning of the string. Works for first line of file, and prevents partial replacement e.g. llo replacing Hello:
(\n|^)
And this one matches a carriage return or the end of the string. This works for cases where there is no newline at the end of the file, and also prevents Hel replacing Hello:
(\r|$)
That should ensure that you are always taking out an entire line that matches your args.
I also eliminated the second readFile as it wasn't necessary to get it to work.
const fs = require("fs")
fs.readFile("notredeemed.txt", function (err, data) {
if (err) throw err
const match = new RegExp(`(\n|^)${args[0]}(\r|$)`)
const newFile = data.toString().replace(match, ``)
fs.writeFile("notredeemed.txt", newFile, "utf8", function (err) {
if (err) return console.log(err)
console.log("true")
})
})
Here is my solution.
Algorithm:
Split the file content into individual lines with your desired End of Line Flag (generally "\n" or "\r\n")
Filter all the lines that you want to delete
Join all the filtered lines back together with the EOL flag
const replacingLine = "- C/C++ addons with Node-API";
const fileContent = `- V8
- WASI
- C++ addons
- C/C++ addons with Node-API
- C++ embedder API
- C/C++ addons with Node-API
- Corepack`;
const newFileContent = replace({ fileContent, replacingLine });
console.log(newFileContent);
function replace({ fileContent, replacingLine, endOfLineFlag = "\n" }) {
return fileContent
.split(endOfLineFlag)
.filter((line) => line !== replacingLine)
.join(endOfLineFlag);
}

How can I open an Image file using fs in NodeJS?

In my current codes, it does only can read a text file, How can I make an Image (base64) file opened with Photos Application (Windows)? Is there any chance to do that? If it's impossible, please let me know!
const fs = require('fs')
fs.readFile('./Test/a.txt', 'utf8' , (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data)
return
})
Another possible solution is like this:
const cp = require('child_process');
const imageFilePath = '/aaa/bbb/ccc'
const c = cp.spawn('a_program_that_opens_images', [ `"${imageFilePath}"` ]);
c.stdout.pipe(process.stdout);
c.stderr.pipe(process.stderr);
c.once('exit', exitCode => {
// child process has exited
});
Do something like this:
const cp = require('child_process');
const c = cp.spawn('bash'); // 1
const imageFilePath = '/aaa/bbb/ccc'
c.stdin.end(`
program_that_opens_images "${imageFilePath}"
`); // 2
c.stdout.pipe(process.stdout); // 3
c.stderr.pipe(process.stderr);
c.once('exit', exitCode => { // 4
// child process has exited
});
what it does:
spawns a bash child process (use sh or zsh instead if you want)
writes to bash stdin, (inputting the command to run)
pipes the stdio from the child to the parent
captures the exit code from the child

Problem using child-process vs terminal while executing a command

I try to execute a command using a child-process and I can't execute by absolute path using nodejs, but when I use terminal, everything is fine.
Why is that?
My code is right here:
const cp = require('child_process');
const commandExecutor = 'node-install/target/node/yarn/dist/bin/yarn.exe';
const symlinkFolder = 'node-install/target/node/target/symlink';
const workingDirectories = [];
Array.from(process.argv).forEach((value, index) => {
if (index >= 2) {
workingDirectories[index - 2] = value;
}
});
workingDirectories.forEach(function(workingDirectory) {
const argumentsUnlink = 'unlink #item# --link-folder ' + symlinkFolder + ' --cwd ' + workingDirectory;
const unlinkCommand = commandExecutor + ' ' + argumentsUnlink;
const execution = cp.exec(
unlinkCommand,
function (error, stdout, stderr) {
console.log(stdout);
console.log(error);
console.log(stderr);
});
execution.on('exit', function (code) {
let message = 'Child process exited with exit code ' + code + ' on route ' + workingDirectory;
console.log(message);
});
});
An example of command is:
node-install/target/node/yarn/dist/bin/yarn.exe unlink #item# --link-folder node-install/target/node/target/symlink --cwd appointments/target/generated-sources/frontend/
But the error I've got is:
'node-install' is not recognized as an internal or external command, operable program or batch file.
While I execute command from terminal, everything is fine.
One of the possible problems - NodeJs unable to locate the file by relative path. You can use construct absolute path to fix this, few options to help if node-install is located in your project root (not ultimate list):
__dirname, which returns the directory of current module, so if
node-install/../..
index.js
then in index.js we can use
const commandExecutor = `${__dirname}/node-install/target/node/yarn/dist/bin/yarn.exe`;
process.cwd(), which returns full path of the process root, so if you start nodejs from folder having node-install, then you can refer to exe like this:
const commandExecutor = `${process.cwd()}/node-install/target/node/yarn/dist/bin/yarn.exe`;

Discord.JS - List all files within a directory as one message

I am having an issue where I cannot seem to find a solution.
I have written a Discord bot from Discord.JS that needs to send a list of file names from a directory as one message. So far I have tried using fs.readddir with path.join and fs.readfilesync(). Below is one example.
const server = message.guild.id;
const serverpath = `./sounds/${server}`;
const fs = require('fs');
const path = require('path');
const directoryPath = path.join('/home/pi/Pablo', serverpath);
fs.readdir(directoryPath, function(err, files) {
if (err) {
return console.log('Unable to scan directory: ' + err);
}
files.forEach(function(file) {
message.channel.send(file);
});
});
Whilst this does send a message of every file within the directory, it sends each file as a separate message. This causes it to take a while due to Discord API rate limits. I want them to all be within the same message, separated with a line break, with a max of 2000 characters (max limit for Discord messages).
Can someone assist with this?
Thanks in advance.
Jake
I recommend using fs.readdirSync(), it will return an array of the file names in the given directory. Use Array#filter() to filter the files down to the ones that are JavaScript files (extentions ending in ".js"). To remove ".js" from the file names use Array#map() to replace each ".js" to "" (effectively removing it entirely) and use Array#join() to join them into a string and send.
const server = message.guild.id;
const serverpath = `./sounds/${server}`;
const { readdirSync } = require('fs');
const path = require('path');
const directoryPath = path.join('/home/pi/Pablo', serverpath);
const files = readdirSync(directoryPath)
.filter(fileName => fileName.endsWith('.js'))
.map(fileName => fileName.replace('.js', ''));
.join('\n');
message.channel.send(files);
Regarding handling the sending of a message greater than 2000 characters:
You can use the Util.splitMessage() method from Discord.JS and provide a maxLength option of 2000. As long as the number of chunks needed to send is not more than a few you should be fine from API ratelimits
const { Util } = require('discord.js');
// Defining "files"
const textChunks = Util.splitMessage(files, {
maxLength: 2000
});
textChunks.forEach(async chunk => {
await message.channel.send(chunk);
});
Built an array of strings (names of files) then join with "\n".
let names = []
fs.readdir(directoryPath, function(err, files) {
if (err) {
return console.log('Unable to scan directory: ' + err);
}
files.forEach(function(file) {
names << file
});
});
message.channel.send(names.join("\n"));

Read a text file using Node.js?

I need to pass in a text file in the terminal and then read the data from it, how can I do this?
node server.js file.txt
How do I pass in the path from the terminal, how do I read that on the other side?
You'll want to use the process.argv array to access the command-line arguments to get the filename and the FileSystem module (fs) to read the file. For example:
// Make sure we got a filename on the command line.
if (process.argv.length < 3) {
console.log('Usage: node ' + process.argv[1] + ' FILENAME');
process.exit(1);
}
// Read the file and print its contents.
var fs = require('fs')
, filename = process.argv[2];
fs.readFile(filename, 'utf8', function(err, data) {
if (err) throw err;
console.log('OK: ' + filename);
console.log(data)
});
To break that down a little for you process.argv will usually have length two, the zeroth item being the "node" interpreter and the first being the script that node is currently running, items after that were passed on the command line. Once you've pulled a filename from argv then you can use the filesystem functions to read the file and do whatever you want with its contents. Sample usage would look like this:
$ node ./cat.js file.txt
OK: file.txt
This is file.txt!
[Edit] As #wtfcoder mentions, using the "fs.readFile()" method might not be the best idea because it will buffer the entire contents of the file before yielding it to the callback function. This buffering could potentially use lots of memory but, more importantly, it does not take advantage of one of the core features of node.js - asynchronous, evented I/O.
The "node" way to process a large file (or any file, really) would be to use fs.read() and process each available chunk as it is available from the operating system. However, reading the file as such requires you to do your own (possibly) incremental parsing/processing of the file and some amount of buffering might be inevitable.
Usign fs with node.
var fs = require('fs');
try {
var data = fs.readFileSync('file.txt', 'utf8');
console.log(data.toString());
} catch(e) {
console.log('Error:', e.stack);
}
IMHO, fs.readFile() should be avoided because it loads ALL the file in memory and it won't call the callback until all the file has been read.
The easiest way to read a text file is to read it line by line. I recommend a BufferedReader:
new BufferedReader ("file", { encoding: "utf8" })
.on ("error", function (error){
console.log ("error: " + error);
})
.on ("line", function (line){
console.log ("line: " + line);
})
.on ("end", function (){
console.log ("EOF");
})
.read ();
For complex data structures like .properties or json files you need to use a parser (internally it should also use a buffered reader).
You can use readstream and pipe to read the file line by line without read all the file into memory one time.
var fs = require('fs'),
es = require('event-stream'),
os = require('os');
var s = fs.createReadStream(path)
.pipe(es.split())
.pipe(es.mapSync(function(line) {
//pause the readstream
s.pause();
console.log("line:", line);
s.resume();
})
.on('error', function(err) {
console.log('Error:', err);
})
.on('end', function() {
console.log('Finish reading.');
})
);
I am posting a complete example which I finally got working. Here I am reading in a file rooms/rooms.txt from a script rooms/rooms.js
var fs = require('fs');
var path = require('path');
var readStream = fs.createReadStream(path.join(__dirname, '../rooms') + '/rooms.txt', 'utf8');
let data = ''
readStream.on('data', function(chunk) {
data += chunk;
}).on('end', function() {
console.log(data);
});
The async way of life:
#! /usr/bin/node
const fs = require('fs');
function readall (stream)
{
return new Promise ((resolve, reject) => {
const chunks = [];
stream.on ('error', (error) => reject (error));
stream.on ('data', (chunk) => chunk && chunks.push (chunk));
stream.on ('end', () => resolve (Buffer.concat (chunks)));
});
}
function readfile (filename)
{
return readall (fs.createReadStream (filename));
}
(async () => {
let content = await readfile ('/etc/ssh/moduli').catch ((e) => {})
if (content)
console.log ("size:", content.length,
"head:", content.slice (0, 46).toString ());
})();

Categories