Convert Files and Folders Structures to Bash Scripts, with NodeJS
Tags: bash, node, javascript, linux
Published: 2021-07-22 14:59:49


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:

```js
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'))
```

</div>
<div class="row">

If **file** is a directory, add an `mkdir -p` command:

```js
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 **file** is binary or text, based on its extension:

```js
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 *textExt* or *binaryExt* arrays.

This is the full NodeJS script:

```js
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 `node index.js test` -> it will generate a Bash script file named *result.sh*

Then, in an empty directory, execute the script with `sh result.sh`.