Created
July 10, 2018 21:54
-
-
Save luveti/531b1dfa7b370d7a15355626aec46c78 to your computer and use it in GitHub Desktop.
Scans a directory recursively for a string and outputs all the matching lines to a file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
const fs = require('fs') | |
const path = require('path') | |
async function walkSync(rootDir) { | |
function readdir(path) { | |
return new Promise((resolve, reject) => { | |
fs.readdir(path, (err, files) => err ? reject(err) : resolve(files)) | |
}) | |
} | |
function stat(path) { | |
return new Promise((resolve, reject) => { | |
fs.stat(path, (err, stats) => err ? reject(err) : resolve(stats)) | |
}) | |
} | |
async function pushStack(baseDir) { | |
stack.push({ baseDir, files: await readdir(baseDir) }) | |
} | |
const results = [] | |
const stack = [] | |
await pushStack(rootDir) | |
while (stack.length > 0) { | |
let { baseDir, files } = stack.pop() | |
for (let file of files) { | |
let relativeFilePath = path.join(baseDir, file) | |
if ((await stat(relativeFilePath)).isDirectory()) { | |
await pushStack(relativeFilePath) | |
} | |
else { | |
results.push(relativeFilePath) | |
} | |
} | |
} | |
return results | |
} | |
async function readFile(path) { | |
return new Promise((resolve, reject) => { | |
fs.readFile(path, (err, data) => err ? reject(err) : resolve(data)) | |
}) | |
} | |
async function writeFile(path, data) { | |
return new Promise((resolve, reject) => { | |
fs.writeFile(path, data, (err) => err ? reject(err) : resolve()) | |
}) | |
} | |
if (process.argv.length < 3) { | |
console.log("Usage: scanny <search string> <root path> <results output file path>") | |
return | |
} | |
const searchString = process.argv[2] | |
const rootPath = path.resolve(process.argv[3] || __dirname) | |
const resultsOutputFilePath = path.resolve(process.argv[4] || "results.txt") | |
process.stdout.write(`Scanning ${rootPath}\n`) | |
;(async function() { | |
let results = [] | |
let filePaths = await walkSync(rootPath) | |
const filePathLength = filePaths.length | |
let i = 0 | |
const now = Date.now() | |
process.stdout.write(`Checking ${filePathLength} files\n`) | |
for (let filePath of filePaths) { | |
process.stdout.write("\u001b[2K\u001b[1000D") | |
process.stdout.write(`Scanning files ${Math.floor((i++ / filePathLength) * 100)}%: ${filePath}`) | |
let data = await readFile(filePath) | |
for (let line of data.toString("utf8").split("\n")) { | |
if (!line.includes(searchString)) continue | |
results.push(line) | |
} | |
} | |
process.stdout.write("\u001b[2K\u001b[1000D") | |
process.stdout.write(`Scanned ${filePathLength} files in ${((Date.now() - now) / 1000).toFixed(2)} seconds\n`) | |
process.stdout.write(`Wrote result to: ${resultsOutputFilePath}\n`) | |
await writeFile(resultsOutputFilePath, results.map(i => i.trim()).join("\n")) | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment