Skip to content

Instantly share code, notes, and snippets.

@luveti
Created July 10, 2018 21:54
Show Gist options
  • Save luveti/531b1dfa7b370d7a15355626aec46c78 to your computer and use it in GitHub Desktop.
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
#!/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