Replace line in file with nodejs

I am using the md5 grunt task to generate MD5 file names. Now I want to rename the sources in the HTML file with the new file name in the task callback. I wonder what the easiest way to do this.

+124
javascript replace gruntjs
Jan 05 '13 at
source share
10 answers

You can use a simple regular expression:

var result = fileAsString.replace(/string to be replaced/g, 'replacement'); 

So...

 var fs = require('fs') fs.readFile(someFile, 'utf8', function (err,data) { if (err) { return console.log(err); } var result = data.replace(/string to be replaced/g, 'replacement'); fs.writeFile(someFile, result, 'utf8', function (err) { if (err) return console.log(err); }); }); 
+234
Jan 06 '13 at 10:12
source share
β€” -

Since the replacement did not work for me, I created a simple package replacement in the npm file to quickly replace the text in one or more files. This is partly based on @asgoth's answer.

Edit (October 3, 2016) : The package now supports promises and globes, and usage instructions have been updated to reflect this.

Editing (March 16, 2018) . The package currently contains over 100,000 downloads per month and has been expanded with additional features as well as the CLI tool.

Installation:

 npm install replace-in-file 

Module required

 const replace = require('replace-in-file'); 

Specify replacement options

 const options = { //Single file files: 'path/to/file', //Multiple files files: [ 'path/to/file', 'path/to/other/file', ], //Glob(s) files: [ 'path/to/files/*.html', 'another/**/*.path', ], //Replacement to make (string or regex) from: /Find me/g, to: 'Replacement', }; 

Asynchronous replacement with promises:

 replace(options) .then(changedFiles => { console.log('Modified files:', changedFiles.join(', ')); }) .catch(error => { console.error('Error occurred:', error); }); 

Asynchronous replacement with callback:

 replace(options, (error, changedFiles) => { if (error) { return console.error('Error occurred:', error); } console.log('Modified files:', changedFiles.join(', ')); }); 

Synchronous Replacement:

 try { let changedFiles = replace.sync(options); console.log('Modified files:', changedFiles.join(', ')); } catch (error) { console.error('Error occurred:', error); } 
+54
Jun 25 '15 at 3:50
source share

Perhaps the replace module ( www.npmjs.org/package/replace ) will work for you as well. This does not require you to read and then write the file.

Adapted from the documentation:

 // install: npm install replace // require: var replace = require("replace"); // use: replace({ regex: "string to be replaced", replacement: "replacement string", paths: ['path/to/your/file'], recursive: true, silent: true, }); 
+30
Aug 01 '14 at 2:39 on
source share

You can also use the sed function, which is part of ShellJS ...

  $ npm install [-g] shelljs require('shelljs/global'); sed('-i', 'search_pattern', 'replace_pattern', file); 

Visit ShellJs.org for more examples.

+24
Jul 16 '14 at 7:33
source share

You can process the file while reading using streams. This is similar to using buffers, but with a more convenient API.

 var fs = require('fs'); function searchReplaceFile(regexpFind, replace, cssFileName) { var file = fs.createReadStream(cssFileName, 'utf8'); var newCss = ''; file.on('data', function (chunk) { newCss += chunk.toString().replace(regexpFind, replace); }); file.on('end', function () { fs.writeFile(cssFileName, newCss, function(err) { if (err) { return console.log(err); } else { console.log('Updated!'); } }); }); searchReplaceFile(/foo/g, 'bar', 'file.txt'); 
+5
Jun 23 '16 at 2:53 on
source share

I ran into problems replacing a small placeholder with a large line of code.

I was doing:

 var replaced = original.replace('PLACEHOLDER', largeStringVar); 

I realized that the problem is with the JavaScript replacement patterns described here . Since the code I used as a replacement string contained $ in it, it interfered with the output.

My solution was to use a function replacement option that DOES NOT perform any special replacement:

 var replaced = original.replace('PLACEHOLDER', function() { return largeStringVar; }); 
+1
Dec 22 '16 at 23:39
source share

ES2017 / 8 for Node 7.6+ with a temporary recording file for atomic replacement.

 const Promise = require('bluebird') const fs = Promise.promisifyAll(require('fs')) async function replaceRegexInFile(file, search, replace){ let contents = await fs.readFileAsync(file, 'utf8') let replaced_contents = contents.replace(search, replace) let tmpfile = `${file}.jstmpreplace` await fs.writeFileAsync(tmpfile, replaced_contents, 'utf8') await fs.renameAsync(tmpfile, file) return true } 

Please note that only for small files, as they will be read in memory.

+1
Oct 27 '17 at 11:34 on
source share

On Linux or Mac, storing is simple and using sed with the shell. External libraries are not required. The following code runs on Linux.

 const shell = require('child_process').execSync shell('sed -i "s!oldString!newString!g" ./yourFile.js') 

The syntax for sed is slightly different on a Mac. I cannot verify this right now, but I believe that you just need to add an empty line after the "-i":

 const shell = require('child_process').execSync shell('sed -i "" "s!oldString!newString!g" ./yourFile.js') 

β€œG” after the finale β€œ!” forces sed to replace all instances in the string. Delete it and only the first occurrence in the line will be replaced.

+1
Mar 20 '19 at 19:39
source share

Instead, I would use a duplex stream. as described here nodejs doc duplex streams

A Transform stream is a duplex stream in which the output is computed in some way from the input.

0
Aug 28 '16 at 9:06 on
source share

If you expand @Sanbor's answer, the most efficient way to do this is to read the source file as a stream, and then also send each chunk to a new file and finally replace the original file with a new file.

 async function findAndReplaceFile(regexFindPattern, replaceValue, originalFile) { const updatedFile = '${originalFile}.updated'; return new Promise((resolve, reject) => { const readStream = fs.createReadStream(originalFile, { encoding: 'utf8', autoClose: true }); const writeStream = fs.createWriteStream(updatedFile, { encoding: 'utf8', autoClose: true }); // For each chunk, do the find & replace, and write it to the new file stream readStream.on('data', (chunk) => { chunk = chunk.toString().replace(regexFindPattern, replaceValue); writeStream.write(chunk); }); // Once we've finished reading the original file... readStream.on('end', () => { writeStream.end(); // emits 'finish' event, executes below statement }); // Replace the original file with the updated file writeStream.on('finish', async () => { try { await _renameFile(originalFile, updatedFile); resolve(); } catch (error) { reject('Error: Error renaming ${originalFile} to ${updatedFile} => ${error.message}); } }); readStream.on('error', (error) => reject('Error: Error reading ${originalFile} => ${error.message})); writeStream.on('error', (error) => reject('Error: Error writing to ${updatedFile} => ${error.message})); }); } async function _renameFile(oldPath, newPath) { return new Promise((resolve, reject) => { fs.rename(oldPath, newPath, (error) => { if (error) { reject(error); } else { resolve(); } }); }); } // Testing it... (async () => { try { await findAndReplaceFile(/"some regex"/g, "someReplaceValue", "someFilePath"); } catch(error) { console.log(error); } })() 
0
Jun 27 '19 at
source share



All Articles