Question

I have a function which generate a shell command which use find to delete all files that are not useful anymore:

DOWNLOAD_DIR = '/home/user/directory';
function purge(psmil, callback) {
    var arg = [DOWNLOAD_DIR, '\\(', '-name', '"*.mp4"', '-o', '-name', '"*.zip"', '\\)', '!', '\\('],
        file = [],
        i = 0;
        cpurge;

    //Fill file with names of the files to keep

    arg.push('-name');
    arg.push('"' + file[i] + '"');
    i = i + 1;
    while( i < file.length) {
        arg.push('-o');
        arg.push('-name');
        arg.push('"' + file[i] + '"');
        i = i + 1;
    }
    arg.push('\\)');
    arg.push('-ls');
    arg.push('-delete');

    cpurge = spawn('find', arg);

    cpurge.stdout.on('data', function(data) {
        console.log('data');
    }
    cpurge.stderr.on('data', function(data) {
        console.log('err: ' + data);
    }
    cpurge.stdout.on('data', function(data) {
        callback();
    }
}

Example, it will generate the command:

find /home/user/directory \( -name "*.mp4" -o -name "*.zip" \) ! \( -name "tokeep.mp4" -o -name "tokeep2.mp4" \) -ls -delete

Which, put in a .sh file and started, work file, it list all .mp4 and .zip in /home/user/directory, print them and delete them

But when I look at the log of my app, it list everything on the disk, and delete all .mp4 and .zip in the directory

Why?

EDIT: Use find directly

I ve tried to use strace, I ve got this line:

2652 execve("/usr/bin/find", ["find", "/home/user/directory/", "\\(", "-name", "\"*.mp4\"", "-o", "-name", "\"*.zip\"", "\\)", "!", "\\(", "-name", "\"filetokeep.mp4", "-o", "-name", "\"filetokeep2.mp4\"", ...], [/* 17 vars */]) = 0
Was it helpful?

Solution

With Bash

When you pass arguments to bash using -c, then the argument just after -c must contain the whole thing you want bash to run. To illustrate, assuming NONEXISTENT does not exist:

$ bash -c ls NONEXISTENT

Will just ls all the files in your directory, no error.

$ bash -c 'ls NONEXISTENT'

Will launch ls NONEXISTENT and will give an error.

So your arg list must be built something like this:

['-c', 'find /home/user/directory \( -name "*.mp4" -o -name "*.zip" \) ! \( -name "tokeep.mp4" -o -name "tokeep2.mp4" \) -ls -delete']

The argument that comes after -c is the whole command you want bash to run.

Without Bash

But as I've said in the comment, I do not see anything in your use of find that should require you pass it to bash. So you could reduce your arg list to just what you want find to execute and spawn find directly. If you decide to do this, you must not quote the arguments you pass to find. So "*.mp4" must become *.mp4 (remove the quotes), \( must become (. The presence of the quotes and the slashes are just for bash. If you no longer use bash, then you must remove them. For instance, this:

'\\(', '-name', '"*.mp4"', '-o', '-name', '"*.zip"', '\\)', '!', '\\('

must become:

'(', '-name', '*.mp4', '-o', '-name', '*.zip', ')', '!', '('

and the same transformation must be applied to the rest of your arguments.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top