Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks, I have hundreds of files. I want to copy the files that do not contain strings of Ns (eg 'NNNN') but ignore the ones that have Ns. I can do it in perl easily. But there must be a single one line command using Linux that I can use. Does anyone how I can do it?

Replies are listed 'Best First'.
Re: grep or perl
by broquaint (Abbot) on Jun 04, 2003 at 12:19 UTC
    Update: now uses -L (not -v) as that'll do the right thing (thanks to nite_man)
    # use -r if you want to process recursively grep -L 'N\+' your_directory | xargs cp --target-directory wherever
    Or a not-quite-one-liner in perl
    perl -MFile::Find::Rule -le 'print for find(file => grep => qr/(?!N\+)/, in => @ARGV)' sourcedir | xargs \ cp --target-directory wherever
    They're untested and assume *nix-esque command-line tools (which should be fine since you're running linux) but that should get you started.
    HTH

    _________
    broquaint

      Many thanks for your suggestion and time. The grep --help command shows the following:
      -v, --invert-match select non-matching lines
      I wish to copy files that do not contain NNNNNs. I am not doing it on a line by line basis. Also I don't understand what the program xargs does also xargs --help does not tell me much.
        I wish to copy files that do not contain NNNNNs.
        Ah yes, sorry you'll want the -L switch as nite_man mentioned. That will output all the files that did not match the criteria.
        Also I don't understand what the program xargs does
        It's roughly equivalent to
        perl -e 'exec "@ARGV " . join " ", <>'
        So execute the given program and provided parameters and then add anything read from the pipe as arguments.
        HTH

        _________
        broquaint

Re: grep or perl
by hawtin (Prior) on Jun 04, 2003 at 13:20 UTC
    I can do it in perl easily...

    Why not just do it in Perl then?

    • Are you worried about performance
    • Do you want to be able to do it when Perl is not available
    • Are you trying to add extra tools to your toolbelt

    Personally if Perl will do it for me then I would use that and move on

Re: grep or perl
by nite_man (Deacon) on Jun 04, 2003 at 12:25 UTC
    Update: It was my mistake :-))
    cd /your/old/dir/
    cp `grep -rl 'NNNN'` * /your/new/dir/
    cp `grep -rl 'NNNN' *` /your/new/dir/
          
    --------------------------------
    SV* sv_bless(SV* sv, HV* stash);
    
      You have a small typo. I guess you meant this:

      cd /your/old/dir/ cp `grep -rl 'NNNN' *` /your/new/dir/

      If one needs another solution for any reason, there is always a for loop:

      for file in `grep -rl 'NNNN' *` ; do cp $file dstdir/ ; done

      Also, this will find files that contain match. Use "-L" in grep, if you want those files which do not contain match.

      Leonid Mamtchenkov aka TVSET

      I used grep -rL instead of l ..... because I want to copy files that do not contain the previously mentioned string. But the number of files seems to stop this command from working. Does anyone have more suggestions?

        This is why another poster suggested xargs. xargs reads arguments from standard input, and executes a command with arguments. It chunks the input and repeats the command as required, to avoid going over any command-line-length limits of the shell.

        Instead of just (xargs --help), try (man xargs) for some examples (search for EXAMPLES) and details.

        --
        [ e d @ h a l l e y . c c ]

        That is why broquaint used xargs. It runs a command for each argument (whitespace separated) it gets on its STDIN. Try reading man xargs

        --

        flounder

        Well, you are right about L but why doesn't grep -rL work? Maybe I didn't understand clearly but I checked this command and all are working correctly.
              
        --------------------------------
        SV* sv_bless(SV* sv, HV* stash);
        
Re: grep or perl
by TomDLux (Vicar) on Jun 04, 2003 at 18:52 UTC

    The Unix way is to use find. (Though, of course, you're allowed to drop the backslashes and have it all on one line.) (It's a lot easier if the directory containing the files has no subdirectories.)

    find $DIR \ -exec egrep 'N+' {} > /dev/null\; -o \ -exec cp {} $otherDir\;

    1 - Run the find command, starting the search at the required directory

    3 - After the nodes above, everyone knows how to find the files which don't contain NNNN. Instead of feeding the names to xargs, we can also implement the action in find>. The return value of egrep is true if the pattern was found, false if it wasn't found, regardless of whether options reverse the send of the search.

    3b - If the pattern matches the file, we want to stop there. That's what the -o option does. We only continue further if the pattern did NOT match anywhere in the file.

    4 - Copy the file to the other directory.

    Note: -exec takes an ordinary command with curly braces where you would have the name of the file, and an escaped semi-colon to mark the end of the -exec.

    More Notes: If the directory has subdirectories, and you don't want to descend into them, it becomes more complicated. You want to -prune directories (-type d), but that stops the search with the first thing found, unless you search depth first (-deepth>) .