An odd behavior of `find`

2019-07-31 03:36发布

问题:

Under my fetch/evs/, there is no sub-folder, I have a command which is supposed to list all the files of fetch/evs/*.ev which don't contain text ' Error:

find . -ipath '*/fetch/evs/*.ev' | xargs grep -L -e "' Error" > try0.txt

This command returns 692 files. What is odd is that it ignores a part of files which satisfy the criteria, for instance if I do:

find . -ipath '*/fetch/evs/grades*.ev' | xargs grep -L -e "' Error" > try1.txt

This command returns 72 files which are not in try0.txt at all.

I really cannot understand this... Could anyone help?

Edit1: I just realize that I omitted a very important information, actually a message is raised after the command: xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option. And the command does stop going through at a file whose name contains '. To correct this, I tried:

find . -ipath '*/fetch/evs/*.ev' | xargs -0 grep -L -e "' Error" > try3.txt

which returns xargs: argument line too long and 0 file.

I also tried:

find . -ipath '*/fetch/evs/*.ev' -print0 | xargs -0 grep -L -e "' Error" > try4.txt

which does not stop at all....

Does anyone have any idea?

回答1:

You won't run into the xargs: argument line too long issue if you were to use -exec.

Say:

find . -ipath '*/fetch/evs/*.ev' -exec sh -c "grep -L -e \"' Error\" {}" \;

Using sh takes care of the single quote in the grep pattern.

EDIT: Without sh:

find . -ipath '*/fetch/evs/*.ev' -exec grep -L -e "' Error" {} \;


回答2:

This isn't precisely an answer, but it is too long to make into a comment, too.

Here's a Perl script that creates a simulation of your situation:

#!/usr/bin/env perl
use strict;
use warnings;
use File::Path qw(make_path);

my $subdir = "./fetch/evs";

make_path($subdir);

for my $i (0..999)
{
    {
    my $file1 = sprintf("%s/spare-%.3d.ev", $subdir, $i);
    open my $fh, '>', $file1 or die;
    printf $fh "Nothing to look at here\n" if ($i % 2 == 0);
    printf $fh "There is an ' Error ' here\n" if ($i % 2 == 1);
    close $fh;
    }
    {
    my $file2 = sprintf("%s/grades-%.3d.ev", $subdir, $i);
    open my $fh, '>', $file2 or die;
    printf $fh "Nothing to look at here\n" if ($i % 2 == 0);
    printf $fh "There is an ' Error ' here\n" if ($i % 2 == 1);
    close $fh;
    }
}

It creates 1,000 files with names spare-000.ev to spare-999.ev, and also grades-000.ev to grades-999.ev in a subdirectory fetch/evs (which it creates if necessary). The odd-numbered files contain the string ' Error; the even numbered files do not.

Running on Mac OS X 10.8.5:

find . -ipath '*/fetch/evs/grades*.ev' | xargs grep -L -e "' Error"

lists all the even numbered files (which don't contain the tag string) and

find . -ipath '*/fetch/evs/grades*.ev' | xargs grep -l -e "' Error"

lists all the odd numbered files (which do contain the tag string). So, on Mac OS X, your problem does not reproduce. Does the script work OK on your machine? (Create a fresh sub-directory or at least move the existing one out of sight.)

If these commands work on your machine, then there is something else about those files you did list. If these commands don't work on your machine, there is a fundamental problem with your machine (when did you last reboot?).

Then whe



回答3:

This part of your problem;

which returns xargs: argument line too long and 0 file.

is that find returns too many files to fit onto the max command line length. Can be addressed with the -n option for xargs;

find . [snip] | xargs -n 5 ...

will cause xargs to repeatedly execute ... with only 5 file names instead of all of them.