This is a simple NodeJS app that takes a source folder as input and generates a Bash script. The Bash script has all the files' content and the folders' structure in the source folder, and it can recreate them when executed. Source code available here: https://github.com/alexadam/folders-to-script First step, iterate through all files in the source folder: const fs = require("fs") const path = require("path") const listFiles = (dirPath, result) => { files = fs.readdirSync(dirPath) result = result || ['#!/bin/sh'] for (const file of files) { ///... } return result } const allFiles = listFiles(rootPath) fs.writeFileSync('./result.sh', allFiles.join('\n')) If is a directory, add an command: file mkdir -p for (const file of files) { if (fs.statSync(dirPath + "/" + file).isDirectory()) { result.push(`mkdir -p ${path.join(dirPath, "/", file).replace(rootPath, '.')}`) result = listFiles(dirPath + "/" + file, result) } } Else, test if is binary or text, based on its extension: file const textExt = ['txt', 'md', 'html', 'json', 'js', 'jsx', 'ts', 'tsx']; const binaryExt = ['jpg', 'png', 'gif', 'pdf', 'mp3', 'mp4']; const getFileExt = (filePath) => filePath.split('.').pop() ... else { const filePath = path.join(dirPath, "/", file); const fileExt = getFileExt(filePath); const fileContent = fs.readFileSync(filePath); if (textExt.includes(fileExt)) { result.push(` cat > ${path.join(dirPath, "/", file).replace(rootPath, '.')} << "EOF" ${fileContent} EOF `) } else if (binaryExt.includes(fileExt)) { const bindata = fileContent.toString('binary'); const hexdata = new Buffer(bindata, 'ascii').toString('hex'); result.push(`echo '${hexdata}' | xxd -r -p > ${path.join(dirPath, "/", file).replace(rootPath, '.')}`) } } ... Binary files are stored as hex strings. You can add/remove file extensions in the or arrays. textExt binaryExt This is the full NodeJS script: const fs = require("fs") const path = require("path") const rootPath = process.argv[2] const textExt = ['txt', 'md', 'html', 'json', 'js', 'jsx', 'ts', 'tsx']; const binaryExt = ['jpg', 'png', 'gif', 'pdf', 'mp3', 'mp4']; const getFileExt = (filePath) => filePath.split('.').pop() const listFiles = (dirPath, result) => { files = fs.readdirSync(dirPath) result = result || ['#!/bin/sh'] for (const file of files) { if (fs.statSync(dirPath + "/" + file).isDirectory()) { result.push(`mkdir -p ${path.join(dirPath, "/", file).replace(rootPath, '.')}`) result = listFiles(dirPath + "/" + file, result) } else { const filePath = path.join(dirPath, "/", file); const fileExt = getFileExt(filePath); const fileContent = fs.readFileSync(filePath); if (textExt.includes(fileExt)) { result.push(` cat > ${path.join(dirPath, "/", file).replace(rootPath, '.')} << "EOF" ${fileContent} EOF `) } else if (binaryExt.includes(fileExt)) { const bindata = fileContent.toString('binary'); const hexdata = new Buffer(bindata, 'ascii').toString('hex'); result.push(`echo '${hexdata}' | xxd -r -p > ${path.join(dirPath, "/", file).replace(rootPath, '.')}`) } } } return result } const allFiles = listFiles(rootPath) fs.writeFileSync('./result.sh', allFiles.join('\n')) Test it with -> it will generate a Bash script file named node index.js test result.sh Then, in an empty directory, execute the script with . sh result.sh Also published on . https://alexadam.dev/blog/folder-structure-script.html