Reputation: 1848
Is there a simple way to move all the files in a directory up to its parent directory then delete the directory?
I'm doing a zip extraction and the source zip contains a root folder called archive
, so when I extract I get extract_path/archive/
, but I'd like to just extract the contents of archive
directly to extract_path
.
I thought this would be simple rename, but the following is throwing a "There is a file in the way" error message.
fs.renameSync(extractPath + "/archive", extractPath)
Upvotes: 17
Views: 24570
Reputation: 496
mv
package isn't really up to date and maintained anymore.
I would suggest:
async function moveFolder(oldPath, newPath) {
console.log(`Try moving ${oldPath} to ${newPath}`)
if (!fs.existsSync(oldPath)) {
console.log(`${oldPath} does not exist`)
return
}
if (!fs.existsSync(newPath)) {
console.log(`Moving ${oldPath} to ${newPath}`)
fs.renameSync(oldPath, newPath)
return
}
const files = fs.readdirSync(oldPath)
for (var key in files) {
const file = files[key]
const oldFilePath = path.join(oldPath, file)
const newFilePath = path.join(newPath, file)
console.log(`Moving ${oldFilePath} to ${newFilePath}`)
fs.renameSync(oldFilePath, newFilePath)
})
}
Upvotes: 0
Reputation: 5662
Non of the answers work for me, I looked deep in mv's code and found my solution:
I move folder/subfolder
to folder
, so the folder already exists.
mv(oldPath, newPath, {mkdirp: false, clobber: false}, (err) => {
if (err) {
throw err;
}
});
Remember if the filename already exists in parent folder it will overwrite by file inside subfolder.
Upvotes: 2
Reputation: 3817
The selected answer does not work:
var mv = require('mv');
var extractPath = 'E:\\tmp\\dir';
mv(extractPath + "\\sub", extractPath, {mkdirp: true}, console.error);
It errors with:
{ Error: EPERM: operation not permitted, rename 'E:\tmp\dir\sub' -> 'E:\tmp\dir'
at Error (native)
errno: -4048,
code: 'EPERM',
syscall: 'rename',
path: 'E:\\tmp\\dir\\sub',
dest: 'E:\\tmp\\dir' }
Use fs-extra instead of mv:
var fs = require('fs-extra');
var extractPath = 'E:\\tmp\\dir';
fs.move(extractPath + "\\sub", extractPath, console.error);
My file structure is like this before the move:
E:\tmp\dir
> sub
> doc.txt
And like this after the move:
E:\tmp\dir
> doc.txt
UPDATE:
While the above works on Windows, on Linux I get the same error even when using fs-extra. The below is a manual fix for this, by individually moving each child of the subdirectory up to the parent. If a child move fails, then it will revert any other successful moves back to the original location in the subdirectory.
var fs = require('fs-extra')
var Promise = require('promise');
var path = require('path');
var promiseAllWait = function(promises) {
// this is the same as Promise.all(), except that it will wait for all promises to fulfill before rejecting
var all_promises = [];
for(var i_promise=0; i_promise < promises.length; i_promise++) {
all_promises.push(
promises[i_promise]
.then(function(res) {
return { res: res };
}).catch(function(err) {
return { err: err };
})
);
}
return Promise.all(all_promises)
.then(function(results) {
return new Promise(function(resolve, reject) {
var is_failure = false;
var i_result;
for(i_result=0; i_result < results.length; i_result++) {
if (results[i_result].err) {
is_failure = true;
break;
} else {
results[i_result] = results[i_result].res;
}
}
if (is_failure) {
reject( results[i_result].err );
} else {
resolve(results);
}
});
});
};
var movePromiser = function(from, to, records) {
return fs.move(from, to)
.then(function() {
records.push( {from: from, to: to} );
});
};
var moveDir = function(from_dir, to_dir) {
return fs.readdir(from_dir)
.then(function(children) {
return fs.ensureDir(to_dir)
.then(function() {
var move_promises = [];
var moved_records = [];
var child;
for(var i_child=0; i_child < children.length; i_child++) {
child = children[i_child];
move_promises.push(movePromiser(
path.join(from_dir, child),
path.join(to_dir, child),
moved_records
));
}
return promiseAllWait(move_promises)
.catch(function(err) {
var undo_move_promises = [];
for(var i_moved_record=0; i_moved_record < moved_records.length; i_moved_record++) {
undo_move_promises.push( fs.move(moved_records[i_moved_record].to, moved_records[i_moved_record].from) );
}
return promiseAllWait(undo_move_promises)
.then(function() {
throw err;
});
});
}).then(function() {
return fs.rmdir(from_dir);
});
});
};
Upvotes: 7
Reputation: 12389
use the mv npm module. mv first tries a fs.rename, and if it fails, uses copy then unlink :
mv('source/dir', 'dest/a/b/c/dir', {mkdirp: true}, function(err) {
// done. it first created all the necessary directories, and then
// tried fs.rename, then falls back to using ncp to copy the dir
// to dest and then rimraf to remove the source dir
});
or spawn a child process :
var spawn = require('child_process').spawn,
mv = spawn('mv', ['/dir1/dir2/*','dir1/']);
Upvotes: 5