Skip to content

Instantly share code, notes, and snippets.

@liangzan
Created February 2, 2011 14:12
Show Gist options
  • Save liangzan/807712 to your computer and use it in GitHub Desktop.
Save liangzan/807712 to your computer and use it in GitHub Desktop.
A Node.js script to remove all files in a directory recursively
var fs = require('fs')
, path = require('path')
, _ = require('underscore');
var rootPath = "/path/to/remove";
removeDirForce(rootPath);
// path should have trailing slash
function removeDirForce(dirPath) {
fs.readdir(dirPath, function(err, files) {
if (err) {
console.log(JSON.stringify(err));
} else {
if (files.length === 0) {
fs.rmdir(dirPath, function(err) {
if (err) {
console.log(JSON.stringify(err));
} else {
var parentPath = path.normalize(dirPath + '/..') + '/';
if (parentPath != path.normalize(rootPath)) {
removeDirForce(parentPath);
}
}
});
} else {
_.each(files, function(file) {
var filePath = dirPath + file;
fs.stat(filePath, function(err, stats) {
if (err) {
console.log(JSON.stringify(err));
} else {
if (stats.isFile()) {
fs.unlink(filePath, function(err) {
if (err) {
console.log(JSON.stringify(err));
}
});
}
if (stats.isDirectory()) {
removeDirForce(filePath + '/');
}
}
});
});
}
}
});
}
@mader80
Copy link

mader80 commented Feb 28, 2012

I am not able to get this to work. It will fail based on the fact that if something is a directory, the function will call itself, remove that directory and then stop running. Not to mention the fact that the stats.isDirectory is returning true for files.

@guybedford
Copy link

Here's a synchronous version:

    rmDir = function(dirPath) {
      try { var files = fs.readdirSync(dirPath); }
      catch(e) { return; }
      if (files.length > 0)
        for (var i = 0; i < files.length; i++) {
          var filePath = dirPath + '/' + files[i];
          if (fs.statSync(filePath).isFile())
            fs.unlinkSync(filePath);
          else
            rmDir(filePath);
        }
      fs.rmdirSync(dirPath);
    };

@Diullei
Copy link

Diullei commented Jan 21, 2013

@guybedford nice!

@vasiliyb
Copy link

@guybedford, ty :)

@iserdmi
Copy link

iserdmi commented Dec 5, 2014

Maybe it will be usefull for someone. Extend @guybedfrod function, to remove all in dir but not dir itself.

    rmDir = function(dirPath, removeSelf) {
      if (removeSelf === undefined)
        removeSelf = true;
      try { var files = fs.readdirSync(dirPath); }
      catch(e) { return; }
      if (files.length > 0)
        for (var i = 0; i < files.length; i++) {
          var filePath = dirPath + '/' + files[i];
          if (fs.statSync(filePath).isFile())
            fs.unlinkSync(filePath);
          else
            rmDir(filePath);
        }
      if (removeSelf)
        fs.rmdirSync(dirPath);
    };

Call rmDir('path/to/dir') to remove all inside dir and dir itself. Call rmDir('path/to/dir', false) to remove all inside, but not dir itself.

@willemx
Copy link

willemx commented Jan 23, 2015

you could replace:

var filePath = dirPath + '/' + files[i];

with:

var filePath = path.join(dirPath, files[i]);

and then it might even work on Windows...

@plwalters
Copy link

That crawler and destroyer that @guybedford posted works great, just be careful to not have any npm links or symlinks for that matter :) Found that out the hard way.

Copy link

ghost commented Jun 19, 2016

@guybedford : Time saving 'code block',thank you.

@jameymcelveen
Copy link

Thanks! Need change rootPath to dirPath here L20

@narainsagar
Copy link

@liangzan Nice. 👍

@richie50
Copy link

richie50 commented Aug 3, 2017

@guybedford Bless your soul

@OddMorning
Copy link

I made an async/await version of @guybedford's code with some changes based on @iserdmi's, @willemx's, and @PWKad's comments.

It can accept object as a second argument that can allow delete just folder's content with { removeContentOnly: true } or allow drilling symbolic links down with { drillDownSymlinks: true } (by default it just deletes a symlink, not its content)

Usage: await rmdir('some/path') or await rmdir('some/path', { (optionsDescridedAbove) })

let rmdir = async (dirPath, options = {}) => {
  const
    { removeContentOnly = false, drillDownSymlinks = false } = options,
    { promisify } = require('util'),
    path = require('path'),
    fs = require('fs'),
    readdirAsync = promisify(fs.readdir),
    unlinkAsync = promisify(fs.unlink),
    rmdirAsync = promisify(fs.rmdir),
    lstatAsync = promisify(fs.lstat) // fs.lstat can detect symlinks, fs.stat can't
  let
    files

  try {
    files = await readdirAsync(dirPath)
  } catch (e) {
    throw new Error(e)
  }

  if (files.length) {
    for (let fileName of files) {
      let
        filePath = path.join(dirPath, fileName),
        fileStat = await lstatAsync(filePath),
        isSymlink = fileStat.isSymbolicLink(),
        isDir = fileStat.isDirectory()

      if (isDir || (isSymlink && drillDownSymlinks)) {
        await rmdir(filePath)
      } else {
        await unlinkAsync(filePath)
      }
    }
  }

  if (!removeContentOnly)
    await rmdirAsync(dirPath)
}

@rubanraj54
Copy link

Here's a synchronous version:

    rmDir = function(dirPath) {
      try { var files = fs.readdirSync(dirPath); }
      catch(e) { return; }
      if (files.length > 0)
        for (var i = 0; i < files.length; i++) {
          var filePath = dirPath + '/' + files[i];
          if (fs.statSync(filePath).isFile())
            fs.unlinkSync(filePath);
          else
            rmDir(filePath);
        }
      fs.rmdirSync(dirPath);
    };

This worked for me.

@bojangles-m
Copy link

bojangles-m commented Sep 2, 2020

A bit more structured :)

const {
  readdirSync,
  rmdirSync,
  unlinkSync,
} = require('fs');
const { join } = require('path');

const isDir = path => {
  try {
    return statSync(path).isDirectory();
  } catch (error) {
    return false;
  }
};

const getFiles = (path) =>
  readdirSync(path)
    .map(name => join(path, name));

const getDirectories = path =>
  readdirSync(path)
    .map(name => join(path, name))
    .filter(isDir);

const rmDir = path => {
  getDirectories(path).map(dir => rmDir(dir));
  getFiles(path).map(file => unlinkSync(file));
  rmdirSync(path);
};

@dudeman9801
Copy link

@iserdmi Thanks. I needed a version that wouldn't delete the directory itself.

@vmengh
Copy link

vmengh commented Apr 21, 2021

Maybe it will be usefull for someone. Extend @guybedfrod function, to remove all in dir but not dir itself.

    rmDir = function(dirPath, removeSelf) {
      if (removeSelf === undefined)
        removeSelf = true;
      try { var files = fs.readdirSync(dirPath); }
      catch(e) { return; }
      if (files.length > 0)
        for (var i = 0; i < files.length; i++) {
          var filePath = dirPath + '/' + files[i];
          if (fs.statSync(filePath).isFile())
            fs.unlinkSync(filePath);
          else
            rmDir(filePath);
        }
      if (removeSelf)
        fs.rmdirSync(dirPath);
    };

Call rmDir('path/to/dir') to remove all inside dir and dir itself. Call rmDir('path/to/dir', false) to remove all inside, but not dir itself.

This is helpful. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment