I want to delete several files from a directory, matching a regex. Something like this:
// WARNING: not real code
require('fs').unlink(/script\.\d+\.js$/);
Since unlink doesn't support regexes, I'm using this instead:
var fs = require('fs');
fs.readdir('.', (error, files) => {
if (error) throw error;
files.filter(name => /script\.\d+\.js$/.test(name)).forEach(fs.unlink);
});
which works, but IMO is a little more complex than it should be.
Is there a better built-in way to delete files that match a regex (or even just use wildcards)?
No there is no globbing in the Node libraries. If you don't want to pull in something from NPM then not to worry, it just takes a line of code. But in my testing the code provided in other answers mostly won't work. So here is my code fragment, tested, working, pure native Node and JS.
let fs = require('fs')
const path = './somedirectory/'
let regex = /[.]txt$/
fs.readdirSync(path)
.filter(f => regex.test(f))
.map(f => fs.unlinkSync(path + f))
You can look into glob https://npmjs.org/package/glob
require("glob").glob("*.txt", function (er, files) { ... });
//or
files = require("glob").globSync("*.txt");
glob internally uses minimatch. It works by converting glob expressions into JavaScript RegExp objects. https://github.com/isaacs/minimatch
You can do whatever you want with the matched files in the callback (or in case of globSync the returned object).
I have a very simple solution to do this. Read the directory in node.js using fs.readdir API. This will give an array of all the files in the directory. Once you have that array, iterate over it using for loop, apply regex.
The below code will delete all files starting with "en" and extension ".js"
fs.readdir('.', (err, files)=>{
for (var i = 0, len = files.length; i < len; i++) {
var match = files[i].match(/en.*.js/);
if(match !== null)
fs.unlink(match[0]);
}
});
The answer could depend on your environment. It looks like you are running on node.js. A quick perusal of the node.js documentation suggests there is no "built in" way to do this, i.e., there isn't a single function call that will do this for you. The next best thing might involve a small number of function calls. As I wrote in my comment, I don't think there's any easy way to make your suggested answer much briefer just relying on the standard node.js function calls. That is, if I were in your shoes, I would go with the solution you already suggested (though slightly cleaned up).
One alternative is to go to the shell, e.g.,
var exec = require('child_process').exec;
exec('ls | grep "script[[:digit:]]\\\+.js" | xargs rm');
Personally, I would strongly prefer your offered solution over this gobbledygook, but maybe you're shooting for something different.
Related
Is there something on npm or in VS Code or anywhere that can bundle or concatenate Javascript files based on comments, like:
function myBigLibrary(){
//#include util.js
//#include init.js
function privateFunc(){...}
function publicFunc(){
//#include somethingElse.js
...
}
return {
init, publicFunc, etc
}
}
Or something like that? I would think that such a thing is common when your javascript files get very large. All I can find are complicated things like webpack.
I'm looking for any equivalent solution that allows you to include arbitrary code in arbitrary positions in other code. I suppose that would cause trouble for intellisense, but an extension could handle that.
I'm not sure what you really means but if you means linking variables from other javascript files. probably this will help you
const { variable name } = require(the javascript file path)
example:
in index.js
const { blue } = require('./../js/blue.js)
console.log(blue)
Meanwhile in blue.js
const blue = "dumbass"
if this doesnt help you just ignore this
So here is a bare bones way to to what I wanted. I have been learning more about how you can do things with esbuild or other bundlers, but I didn't quite figure out something that fit my needs. And this is simpler and more flexible. It can work for any file type. You can do automatic updates when files change using nodemon instead of node to run this code.
const fs = require('fs')
/////////////////////////
const input = 'example.js'
const output = 'output.js'
const ext = '.js'
// looks for file with optional directory as: //== dir/file
const regex = /\/\/== *([\w-\/]+)/g
const fileContent = fs.readFileSync(input).toString()
// replace the comment references with the corresponding file content
const replacement = fileContent.replace(regex, (match, group)=>{
const comment = '//////// '+group+ext+' ////////\n\n'
const replace = fs.readFileSync(group+ext).toString()
return comment + replace
})
// write replacement to a file
fs.writeFileSync(output, replacement)
In node.js, can I list files with wild card matching like
fs.readdirSync('C:/tmp/*.csv')?
I did not find the information on wild card matching from the fs documention.
If you don't want to add a new dependency to your project (like glob), you can use plain js/node functions, like:
var files = fs.readdirSync('C:/tmp').filter(fn => fn.endsWith('.csv'));
Regex may help in more complex comparisons
This is not covered by Node core. You can check out this module for what you are after.
Setup
npm i glob
Usage
var glob = require("glob")
// options is optional
glob("**/*.js", options, function (er, files) {
// files is an array of filenames.
// If the `nonull` option is set, and nothing
// was found, then files is ["**/*.js"]
// er is an error object or null.
})
If glob is not quite what you want, or a little confusing, there is also glob-fs. The documentation covers many usage scenarios with examples.
// sync
var files = glob.readdirSync('*.js', {});
// async
glob.readdir('*.js', function(err, files) {
console.log(files);
});
// stream
glob.readdirStream('*.js', {})
.on('data', function(file) {
console.log(file);
});
// promise
glob.readdirPromise('*.js')
.then(function(files) {
console.log(file);
});
Just in case you want to search files by regex (for complex matches), then consider using file-regex, which supports recursive search and concurrency control (for faster results).
Sample usage
import FindFiles from 'file-regex'
// This will find all the files with extension .js
// in the given directory
const result = await FindFiles(__dirname, /\.js$/);
console.log(result)
Pretty straightforward with match out of the box
import fs from 'fs'
fs.readdirSync('C:/tmp/').filter((allFilesPaths:string) =>
allFilesPaths.match(/\.csv$/) !== null)
dont reinvent the wheel, if you are on *nix the ls tool can easily do this (node api docs)
var options = {
cwd: process.cwd(),
}
require('child_process')
.exec('ls -1 *.csv', options, function(err, stdout, stderr){
if(err){ console.log(stderr); throw err };
// remove any trailing newline, otherwise last element will be "":
stdout = stdout.replace(/\n$/, '');
var files = stdout.split('\n');
});
I tried to look for a package that can run a grep filter against an array of string. But I can't find one.
I want to do something like this:
const paths = ['some/file/paths-1', 'some/other/paths', ... ]
const filteredPaths = grep(paths, 'some/file/**/*')
I understand this question is not a good SO question as it can be opinionated and favor a particular package.
But I think many people would look for the same thing.
I found it: https://www.npmjs.com/package/matcher
This is useful if you are getting input from cli or config.
Regex in those cases would be too complicated.
Sometimes finding the right package for the job is hard, it is even harder today with https://github.com/npm/npm/issues/19438
I'd leave the question and answer here so that people can find it a bit easier.
It wouldn't make any sense to try and use grep to solve this. Javascript regexes work just fine.
const paths = ['some/file/paths-1', 'some/other/paths', ... ]
const filteredPaths = paths.filter(path => /^some\/file\/.*/)
if you insist on using grep for this you could do it like so:
const fs = require('fs')
const execSync = require('child_process').execSync
const paths = ['some/file/paths-1', 'some/other/paths']
fs.writeFileSync('/tmp/b', paths.join('\n'), 'utf8')
const grepResult = execSync("grep 'some/file/' /tmp/b")
const filteredPaths = grepResult.toString()
console.log(filteredPaths)
I personally fail to see any situation that this appropriate though
Hi guys im trying to solve the exercises from nodeschool, i started with learnyounode, people recomende it a lot for beginners, the exercise question is this:
# LEARN YOU THE NODE.JS FOR MUCH WIN!
## FILTERED LS (Exercise 5 of 13)
Create a program that prints a list of files in a given directory,
filtered by the extension of the files. You will be provided a directory
name as the first argument to your program (e.g. '/path/to/dir/') and a
file extension to filter by as the second argument.
For example, if you get 'txt' as the second argument then you will need to
filter the list to only files that end with .txt. Note that the second
argument will not come prefixed with a '.'.
Keep in mind that the first arguments of your program are not the first
values of the process.argv array, as the first two values are reserved for
system info by Node.
The list of files should be printed to the console, one file per line. You
must use asynchronous I/O.
─────────────────────────────────────────────────────────────────────────────
## HINTS
The fs.readdir() method takes a pathname as its first argument and a
callback as its second. The callback signature is:
function callback (err, list) { /* ... */ }
where list is an array of filename strings.
Documentation on the fs module can be found by pointing your browser here:
file://C:\Users\Filipe\AppData\Roaming\npm\node_modules\learnyounode\node_
apidoc\fs.html
You may also find node's path module helpful, particularly the extname
method.
Documentation on the path module can be found by pointing your browser
here:
file://C:\Users\Filipe\AppData\Roaming\npm\node_modules\learnyounode\node_
apidoc\path.html
─────────────────────────────────────────────────────────────────────────────
» To print these instructions again, run: learnyounode print
» To execute your program in a test environment, run: learnyounode run
program.js
» To verify your program, run: learnyounode verify program.js
» For help run: learnyounode help
i tried to solve the exercise doing this:
var fs = require('fs');
fs.readdir(process.argv[2],process.argv[3],function(err,list){
for(var i = 0;i<list.length;i++)
{
var fileParts = list[i].split(".");
if(fileParts[1] == process.argv[3]){
console.log(list[i] + "\n");
}
}
});
why it doesnt work, i dont know what i am doing wrong, if someone can give me a tip to solve this i appreciate a lot, since the solutions on web are quite bit strange.
Hm, I just tested your code and it actually runs fine for me. Verify returns with solved. Not sure what you are experiencing. Btw.: put in at least some error handling. Below my solution:
const fs = require('fs');
const test = '.' + process.argv[3]
fs.readdir(process.argv[2], (err, data) => {
if (err) {
console.error(err);
} else {
data.filter(file => {
if (file.substring(file.length - test.length) === test) {
console.log(file)
}
})
}
});
Is there a way you can copy to clipboard in Node.js? Any modules or ideas what so ever? I'm using Node.js on a desktop application. Hopefully that clears up why I want it to be able to achieve this.
For OS X:
function pbcopy(data) {
var proc = require('child_process').spawn('pbcopy');
proc.stdin.write(data); proc.stdin.end();
}
write() can take a buffer or a string. The default encoding for a string will be utf-8.
Check out clipboardy. It lets you copy/paste cross-platform. It is more actively maintained than the copy-paste module mentioned in another answer and it fixes many of that module's issues.
const clipboardy = require('clipboardy');
// Copy
clipboardy.writeSync('🦄');
// Paste
clipboardy.readSync();
//🦄
Here's a module that provide copy and paste functions: https://github.com/xavi-/node-copy-paste
When require("copy-paste").global() is executed, two global functions are added:
> copy("hello") // Asynchronously adds "hello" to clipbroad
> Copy complete
> paste() // Synchronously returns clipboard contents
'hello'
Like many of the other answer mentioned, to copy and paste in node you need to call out to an external program. In the case of node-copy-paste, it calls out to pbcopy/pbpaste (for OSX), xclip (for linux), and clip (for windows).
This module was very helpful when I was doing a lot of work in the REPL for a side project. Needless to say, copy-paste is only a command line utility -- it is not meant for server work.
Shortest way in Windows:
const util = require('util');
require('child_process').spawn('clip').stdin.end(util.inspect('content_for_the_clipboard'));
A clipboard is not inherent to an operating system. It's a construct of whatever window system the operating system happens to be running. So if you wanted this to work on X for example, you would need bindings to Xlib and/or XCB. Xlib bindings for node actually exist: https://github.com/mixu/nwm. Although I'm not sure whether it gives you access to the X clipboard, you might end up writing your own. You'll need separate bindings for windows.
edit: If you want to do something hacky, you could also use xclip:
var exec = require('child_process').exec;
var getClipboard = function(func) {
exec('/usr/bin/xclip -o -selection clipboard', function(err, stdout, stderr) {
if (err || stderr) return func(err || new Error(stderr));
func(null, stdout);
});
};
getClipboard(function(err, text) {
if (err) throw err;
console.log(text);
});
I managed to do so by creating a different application which handles this. It's certainly not the best way, but it works.
I'm on Windows and created a VB.NET application:
Module Module1
Sub Main()
Dim text = My.Application.CommandLineArgs(0)
My.Computer.Clipboard.SetText(text)
Console.Write(text) ' will appear on stdout
End Sub
End Module
Then in Node.js, I used child_process.exec to run the VB.NET application, with the data to be copied passed as a command line argument:
require('child_process').exec(
"CopyToClipboard.exe \"test foo bar\"",
function(err, stdout, stderr) {
console.log(stdout); // to confirm the application has been run
}
);
Mac has a native command line pbcopy for this usecase:
require('child_process').exec(
'echo "test foo bar" | pbcopy',
function(err, stdout, stderr) {
console.log(stdout); // to confirm the application has been run
}
);
Same code for Linux but replace pbcopy with Xclip (apt get install xclip)
I saw there wasn't a solution here or anywhere obvious that worked for Windows, so reposting this one found in the depths of page 2 on Google search, which uses the Windows native command line clip, and avoids any potentially messy usage of command line workarounds such as echo foo | clip like suggested above.
var cp = require("child_process");
var child = cp.spawn('clip');
child.stdin.write(result.join("\n"));
child.stdin.end();
Hope this helps someone!
This is how you would do this on node-ffi for windows, this interacts directly with the native clipboard API from windows. (Which means you can also read/write different clipboard formats)
var {
winapi,
user32,
kernel32,
constants
} = require('#kreijstal/winffiapi')
const GMEM_MOVEABLE=0x2;
var stringbuffer=Buffer.from("hello world"+'\0');//You need a null terminating string because C api.
var hmem=kernel32.GlobalAlloc(GMEM_MOVEABLE,stringbuffer.length);
var lptstr = kernel32.GlobalLock(hmem);
stringbuffer.copy(winapi.ref.reinterpret(lptstr, stringbuffer.length));
kernel32.GlobalUnlock(hmem);
if (!user32.OpenClipboard(0)){
kernel32.GlobalLock(hmem);
kernel32.GlobalFree(hmem);
kernel32.GlobalUnlock(hmem);
throw new Error("couldn't open clipboard");
}
user32.EmptyClipboard();
user32.SetClipboardData(constants.clipboardFormats.CF_TEXT, hmem);
user32.CloseClipboard();
check this zeroclipboard
npm install zeroclipboard