How can I find files in directories listed in a file?Find both regular files and directoriesDelete all files in directories except those whose path are listed in a fileFind directories without music filesTo count number of matches in a mega string quicklyMove all files from listed directories one level upFind command that excludes paths listed in a fileFind files inside numbered directoriesHow to find directories containing only specific files

How to determine algebraically whether an equation has an infinite solutions or not?

Notice period 60 days but I need to join in 45 days

Force SQL Server to use fragmented indexes?

How to pass 2>/dev/null as a variable?

Counting the triangles that can be formed from segments of given lengths

rationalizing sieges in a modern/near-future setting

Find feasible point in polynomial time in linear programming

Is there a word or phrase that means "use other people's wifi or Internet service without consent"?

What is the name of this plot that has rows with two connected dots?

Why is sh (not bash) complaining about functions defined in my .bashrc?

Are strlen optimizations really needed in glibc?

How to emphasise the insignificance of someone/thing – besides using "klein"

Is it true that different variants of the same model aircraft don't require pilot retraining?

Finding square root without division and initial guess

Why didn't Doc believe Marty was from the future?

Did ancient peoples ever hide their treasure behind puzzles?

Biological refrigeration?

Mathematica equivalent of a curl snippet

Is a memoized pure function itself considered pure?

Count the number of shortest paths to n

Does trying to charm an uncharmable creature cost a spell slot?

Term used to describe a person who predicts future outcomes

How to force GCC to assume that a floating-point expression is non-negative?

How much does Commander Data weigh?



How can I find files in directories listed in a file?


Find both regular files and directoriesDelete all files in directories except those whose path are listed in a fileFind directories without music filesTo count number of matches in a mega string quicklyMove all files from listed directories one level upFind command that excludes paths listed in a fileFind files inside numbered directoriesHow to find directories containing only specific files






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








3















In a directory there are several subdirectories, something like:



TopLevelDir
+-- SubDir1
+-- SubDir2
+-- SubDir3
+-- SubDir4
+-- SubDir5
+-- SubDir6


I need to find files containing some specific text in a specific subset of those subdirectories. What is needed can be accomplished with:



find SubDir1 SubDir2 SubDir4 -type f -exec grep -H "desired text" ;


A similar search will be needed frequently. To save time and typing, I would like to store the names of the subdirectories to be searched in a file and use that when I run the find command next time, something like:



find subdirs2search.txt -type f -name="*.txt" -exec grep -H "desired text" ;


Searching the web, checking man pages, and even checking my *nix book hasn't turned up anything on how to do this.



Is this possible? If so, how can it be done?










share|improve this question





















  • 2





    If you used + to end the -exec instead of ;, you wouldn't need the -H option on the grep command (it's the default if multiple file args are used). More importantly, it would also run noticeably faster because it wouldn't need to fork one grep per file (instead it would run grep with as many filename args as will fit on the command line). find SubDir1 SubDir2 SubDir4 -type f -exec grep "desired text" +

    – cas
    Aug 15 at 3:32







  • 1





    @cas: it's possible that find only finds 1 regular file total, so -H is still a good idea. But yes, -exec ... + is much faster than ; especially for lots of small files where startup overhead matters more.

    – Peter Cordes
    Aug 15 at 5:31












  • @PeterCordes yes, that's true. i didn't think of that :)

    – cas
    Aug 15 at 5:43

















3















In a directory there are several subdirectories, something like:



TopLevelDir
+-- SubDir1
+-- SubDir2
+-- SubDir3
+-- SubDir4
+-- SubDir5
+-- SubDir6


I need to find files containing some specific text in a specific subset of those subdirectories. What is needed can be accomplished with:



find SubDir1 SubDir2 SubDir4 -type f -exec grep -H "desired text" ;


A similar search will be needed frequently. To save time and typing, I would like to store the names of the subdirectories to be searched in a file and use that when I run the find command next time, something like:



find subdirs2search.txt -type f -name="*.txt" -exec grep -H "desired text" ;


Searching the web, checking man pages, and even checking my *nix book hasn't turned up anything on how to do this.



Is this possible? If so, how can it be done?










share|improve this question





















  • 2





    If you used + to end the -exec instead of ;, you wouldn't need the -H option on the grep command (it's the default if multiple file args are used). More importantly, it would also run noticeably faster because it wouldn't need to fork one grep per file (instead it would run grep with as many filename args as will fit on the command line). find SubDir1 SubDir2 SubDir4 -type f -exec grep "desired text" +

    – cas
    Aug 15 at 3:32







  • 1





    @cas: it's possible that find only finds 1 regular file total, so -H is still a good idea. But yes, -exec ... + is much faster than ; especially for lots of small files where startup overhead matters more.

    – Peter Cordes
    Aug 15 at 5:31












  • @PeterCordes yes, that's true. i didn't think of that :)

    – cas
    Aug 15 at 5:43













3












3








3


0






In a directory there are several subdirectories, something like:



TopLevelDir
+-- SubDir1
+-- SubDir2
+-- SubDir3
+-- SubDir4
+-- SubDir5
+-- SubDir6


I need to find files containing some specific text in a specific subset of those subdirectories. What is needed can be accomplished with:



find SubDir1 SubDir2 SubDir4 -type f -exec grep -H "desired text" ;


A similar search will be needed frequently. To save time and typing, I would like to store the names of the subdirectories to be searched in a file and use that when I run the find command next time, something like:



find subdirs2search.txt -type f -name="*.txt" -exec grep -H "desired text" ;


Searching the web, checking man pages, and even checking my *nix book hasn't turned up anything on how to do this.



Is this possible? If so, how can it be done?










share|improve this question
















In a directory there are several subdirectories, something like:



TopLevelDir
+-- SubDir1
+-- SubDir2
+-- SubDir3
+-- SubDir4
+-- SubDir5
+-- SubDir6


I need to find files containing some specific text in a specific subset of those subdirectories. What is needed can be accomplished with:



find SubDir1 SubDir2 SubDir4 -type f -exec grep -H "desired text" ;


A similar search will be needed frequently. To save time and typing, I would like to store the names of the subdirectories to be searched in a file and use that when I run the find command next time, something like:



find subdirs2search.txt -type f -name="*.txt" -exec grep -H "desired text" ;


Searching the web, checking man pages, and even checking my *nix book hasn't turned up anything on how to do this.



Is this possible? If so, how can it be done?







bash find directory-structure






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Aug 15 at 15:44







GreenMatt

















asked Aug 14 at 20:00









GreenMattGreenMatt

4154 silver badges14 bronze badges




4154 silver badges14 bronze badges










  • 2





    If you used + to end the -exec instead of ;, you wouldn't need the -H option on the grep command (it's the default if multiple file args are used). More importantly, it would also run noticeably faster because it wouldn't need to fork one grep per file (instead it would run grep with as many filename args as will fit on the command line). find SubDir1 SubDir2 SubDir4 -type f -exec grep "desired text" +

    – cas
    Aug 15 at 3:32







  • 1





    @cas: it's possible that find only finds 1 regular file total, so -H is still a good idea. But yes, -exec ... + is much faster than ; especially for lots of small files where startup overhead matters more.

    – Peter Cordes
    Aug 15 at 5:31












  • @PeterCordes yes, that's true. i didn't think of that :)

    – cas
    Aug 15 at 5:43












  • 2





    If you used + to end the -exec instead of ;, you wouldn't need the -H option on the grep command (it's the default if multiple file args are used). More importantly, it would also run noticeably faster because it wouldn't need to fork one grep per file (instead it would run grep with as many filename args as will fit on the command line). find SubDir1 SubDir2 SubDir4 -type f -exec grep "desired text" +

    – cas
    Aug 15 at 3:32







  • 1





    @cas: it's possible that find only finds 1 regular file total, so -H is still a good idea. But yes, -exec ... + is much faster than ; especially for lots of small files where startup overhead matters more.

    – Peter Cordes
    Aug 15 at 5:31












  • @PeterCordes yes, that's true. i didn't think of that :)

    – cas
    Aug 15 at 5:43







2




2





If you used + to end the -exec instead of ;, you wouldn't need the -H option on the grep command (it's the default if multiple file args are used). More importantly, it would also run noticeably faster because it wouldn't need to fork one grep per file (instead it would run grep with as many filename args as will fit on the command line). find SubDir1 SubDir2 SubDir4 -type f -exec grep "desired text" +

– cas
Aug 15 at 3:32






If you used + to end the -exec instead of ;, you wouldn't need the -H option on the grep command (it's the default if multiple file args are used). More importantly, it would also run noticeably faster because it wouldn't need to fork one grep per file (instead it would run grep with as many filename args as will fit on the command line). find SubDir1 SubDir2 SubDir4 -type f -exec grep "desired text" +

– cas
Aug 15 at 3:32





1




1





@cas: it's possible that find only finds 1 regular file total, so -H is still a good idea. But yes, -exec ... + is much faster than ; especially for lots of small files where startup overhead matters more.

– Peter Cordes
Aug 15 at 5:31






@cas: it's possible that find only finds 1 regular file total, so -H is still a good idea. But yes, -exec ... + is much faster than ; especially for lots of small files where startup overhead matters more.

– Peter Cordes
Aug 15 at 5:31














@PeterCordes yes, that's true. i didn't think of that :)

– cas
Aug 15 at 5:43





@PeterCordes yes, that's true. i didn't think of that :)

– cas
Aug 15 at 5:43










5 Answers
5






active

oldest

votes


















8















If the directory names are one-per-line, then you could avoid issues with directories that have spaces or tabs or wildcard characters in their names by using readarray (bash v4+):



readarray -t dirs < subdirs2search.txt
find "$dirs[@]" ...


That would still not help if some directory names start with -, but with GNU find, there's no way around that.






share|improve this answer






















  • 2





    Prepending ./ to relative paths would ensure they're not parsed as options.

    – John Kugelman
    Aug 15 at 13:23






  • 1





    @John, unless they are full paths already (starting with /)

    – Jeff Schaller
    Aug 15 at 13:25


















5
















I found that it didn't limit the search to only text files




ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files (determined using heuristics based on file name and content) and will by default skip directories like .git/.svn which if you're a developer is likely what you want. https://beyondgrep.com/.



It's packed by most GNU/Linux distros so it's easy to install. It's written in perl (so its regexps are perl regexps, similar to those of GNU grep -P).



ack -- "desired text" $(<subdirs.txt)


should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.



(Different ways of word-splitting subdirs.txt onto a command line are covered in other answers. You might want to just let the shell's standard word-splitting do it, or readarray to split only on lines and also block glob expansion.)






share|improve this answer



























  • Not the it only properly works with ASCII/ISO8859-1 data (not non-ASCII UTF-8 characters, even with PERL_UNICODE=SLAD which seems to only work for its --filter)

    – Stéphane Chazelas
    Aug 15 at 6:50






  • 1





    PERLIO=':utf8' PERL_UNICODE=A ack 'utf8 text' helps (though makes it significantly slower and reports decoding errors for non-UTF-8 input).

    – Stéphane Chazelas
    Aug 15 at 7:09


















5















Naturally, posting the question helped snap me out of my fixation on doing this strictly with find and made me think of expanding the file via Bash. I'm posting an answer hoping it will help someone else (and also to document this for my own future use).



The incantation for having Bash expand the file contents is $(<subdirs2search.txt). So, if subdirs2search.txt contains:



SubDir1 SubDir2 SubDir4


A command like the following will accomplish the desired search:



find $(<subdirs2search.txt) -type f -name="*.txt" -exec grep -H "desired text" ;





share|improve this answer



























  • Note that it's not specific to bash. The $(<file) operator comes from ksh and is also supported by zsh. In other POSIX-like shells, you can use $(cat file) instead.

    – Stéphane Chazelas
    Aug 14 at 21:02












  • @StéphaneChazelas: Thanks for the input. That said, I've rolled back to my original answer. Testing your solution, I found that it didn't limit the search to only text files, and it ran significantly slower. Also, it is different enough that - IMO - you should submit it as your own answer.

    – GreenMatt
    Aug 14 at 21:20






  • 1





    "I found that it didn't limit the search to only text files", to be fair, neither does your find command.

    – muru
    Aug 15 at 5:30






  • 2





    @muru and Matt: ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files. beyondgrep.com. It's packed by most GNU/Linux distros. e.g. ack "desired text" $(<subdirs.txt) should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.

    – Peter Cordes
    Aug 15 at 5:36






  • 1





    With grep, that's --include='*.txt'

    – muru
    Aug 15 at 15:46


















3















Another tool similar to ack (Peter Cordes's answer) is ripgrep or rg. It supports the same usage:



rg -- "desired text" $(<subdirs2search.txt)


It also skips binary files by default.






share|improve this answer
































    3

















    #!/usr/bin/perl -w

    use strict;
    use File::Find ();

    sub wanted;
    sub process_file ($@);

    my $dirfile = shift; # First argument is the filename containing the list
    # of directories.

    my $pattern = shift; # Second arg is a perl RE containing the pattern to search
    # for. Remember to single-quote it on the command line.

    # Read in the @dirs array from $dirfile
    #
    # A NUL-separated file is best, just in case any of the directory names
    # contained line-feeds. If you're certain that could never happen, a
    # plain-text LF-separated file would do.
    #
    # BTW, you can easily generate a NUL-separated file from the shell with:
    # printf "%s" dir1 dir2 dir3 dir4 $'dirnwithn3nLFs' > dirs.txt

    my @dirs=();


    local $/=""; # delete this line if you want to use a LF-separated file.
    # In that case, the ... block around the code from open to
    # close is no longer needed. It's only there so it's possible
    # to make a local change to the $/ aka $INPUT_RECORD_SEPARATOR
    # variable.

    open(DIRFILE,"<",$dirfile);
    while(<DIRFILE>)
    chomp;
    push @dirs, $_;
    ;
    close(DIRFILE);
    ;

    File::Find::find(wanted => &wanted, @dirs);
    exit;

    sub wanted
    my ($dev,$ino,$mode,$nlink,$uid,$gid);

    (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && -f _ && process_file($_);


    sub process_file ($@)

    # This function currently just greps for pattern in the filename passed to
    # it. As the function name implies, it could be used to process the file
    # in any way, not just grep it.

    my $filename = shift;

    # uncomment the return statement below to skip "binary" files.
    # (note this is a workable but fairly crude test. Perl's File::MMagic
    # module can be used to more accurately identify file types, using the
    # same "magic" file databases as the /usr/bin/file command)

    # return if -B $filename;

    open(FILE,"<",$filename);
    while(<FILE>)
    print "$filename:$_" if (m/$pattern/o) ;
    ;

    close(FILE);



    This uses perl and perl's File::Find module to do the same thing as your find ... -exec grep.



    There's nothing particularly interesting or special about this script except that the process_file function can be very easily modified to do anything you want with or to the file - e.g. change owner or perms, delete it, rename it, insert or delete lines or whatever else you might want.



    e.g. if you wanted to delete files which contain text matching the pattern, you could replace the process_file function with something like this:



    sub process_file ($@) 

    my $filename = shift;
    my $found = 0;

    # uncomment to skip "binary" files:
    return if -B $filename;

    open(FILE,"<",$filename);
    while(<FILE>)
    if (m/$pattern/o)
    $found = 1;
    last;
    ;
    ;

    close(FILE);
    unlink $filename if ($found);



    It's also worth mentioning that the wanted function in this script is currently only looking for regular files (the -f test). Perl's stat and lstat functions provide access to all of the file metadata that find can use to match files (uid, gid, perms, size, atime, mtime, etc) so the wanted function can replicate ANY and all find predicates. see perldoc -f stat and perldoc -f lstat for details.



    BTW, the script was generated initially by find2perl, and then modified substantially to a) read in the list of directories from a file, and b) to do the grep in perl code rather than by forking grep and c) add a lot of comments. Performance should be nearly identical to find ... -exec grep because grep can't open files or do a regexp pattern match significantly faster than perl can. It may even be faster.



    Also BTW, find2perl used to be included with perl, but since perl 5.22 it was removed and can now be found on CPAN at find2perl






    share|improve this answer





























      Your Answer








      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "106"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f535634%2fhow-can-i-find-files-in-directories-listed-in-a-file%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      5 Answers
      5






      active

      oldest

      votes








      5 Answers
      5






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      8















      If the directory names are one-per-line, then you could avoid issues with directories that have spaces or tabs or wildcard characters in their names by using readarray (bash v4+):



      readarray -t dirs < subdirs2search.txt
      find "$dirs[@]" ...


      That would still not help if some directory names start with -, but with GNU find, there's no way around that.






      share|improve this answer






















      • 2





        Prepending ./ to relative paths would ensure they're not parsed as options.

        – John Kugelman
        Aug 15 at 13:23






      • 1





        @John, unless they are full paths already (starting with /)

        – Jeff Schaller
        Aug 15 at 13:25















      8















      If the directory names are one-per-line, then you could avoid issues with directories that have spaces or tabs or wildcard characters in their names by using readarray (bash v4+):



      readarray -t dirs < subdirs2search.txt
      find "$dirs[@]" ...


      That would still not help if some directory names start with -, but with GNU find, there's no way around that.






      share|improve this answer






















      • 2





        Prepending ./ to relative paths would ensure they're not parsed as options.

        – John Kugelman
        Aug 15 at 13:23






      • 1





        @John, unless they are full paths already (starting with /)

        – Jeff Schaller
        Aug 15 at 13:25













      8














      8










      8









      If the directory names are one-per-line, then you could avoid issues with directories that have spaces or tabs or wildcard characters in their names by using readarray (bash v4+):



      readarray -t dirs < subdirs2search.txt
      find "$dirs[@]" ...


      That would still not help if some directory names start with -, but with GNU find, there's no way around that.






      share|improve this answer















      If the directory names are one-per-line, then you could avoid issues with directories that have spaces or tabs or wildcard characters in their names by using readarray (bash v4+):



      readarray -t dirs < subdirs2search.txt
      find "$dirs[@]" ...


      That would still not help if some directory names start with -, but with GNU find, there's no way around that.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Aug 14 at 20:56









      Stéphane Chazelas

      331k58 gold badges648 silver badges1017 bronze badges




      331k58 gold badges648 silver badges1017 bronze badges










      answered Aug 14 at 20:23









      Jeff SchallerJeff Schaller

      49.3k11 gold badges72 silver badges163 bronze badges




      49.3k11 gold badges72 silver badges163 bronze badges










      • 2





        Prepending ./ to relative paths would ensure they're not parsed as options.

        – John Kugelman
        Aug 15 at 13:23






      • 1





        @John, unless they are full paths already (starting with /)

        – Jeff Schaller
        Aug 15 at 13:25












      • 2





        Prepending ./ to relative paths would ensure they're not parsed as options.

        – John Kugelman
        Aug 15 at 13:23






      • 1





        @John, unless they are full paths already (starting with /)

        – Jeff Schaller
        Aug 15 at 13:25







      2




      2





      Prepending ./ to relative paths would ensure they're not parsed as options.

      – John Kugelman
      Aug 15 at 13:23





      Prepending ./ to relative paths would ensure they're not parsed as options.

      – John Kugelman
      Aug 15 at 13:23




      1




      1





      @John, unless they are full paths already (starting with /)

      – Jeff Schaller
      Aug 15 at 13:25





      @John, unless they are full paths already (starting with /)

      – Jeff Schaller
      Aug 15 at 13:25













      5
















      I found that it didn't limit the search to only text files




      ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files (determined using heuristics based on file name and content) and will by default skip directories like .git/.svn which if you're a developer is likely what you want. https://beyondgrep.com/.



      It's packed by most GNU/Linux distros so it's easy to install. It's written in perl (so its regexps are perl regexps, similar to those of GNU grep -P).



      ack -- "desired text" $(<subdirs.txt)


      should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.



      (Different ways of word-splitting subdirs.txt onto a command line are covered in other answers. You might want to just let the shell's standard word-splitting do it, or readarray to split only on lines and also block glob expansion.)






      share|improve this answer



























      • Not the it only properly works with ASCII/ISO8859-1 data (not non-ASCII UTF-8 characters, even with PERL_UNICODE=SLAD which seems to only work for its --filter)

        – Stéphane Chazelas
        Aug 15 at 6:50






      • 1





        PERLIO=':utf8' PERL_UNICODE=A ack 'utf8 text' helps (though makes it significantly slower and reports decoding errors for non-UTF-8 input).

        – Stéphane Chazelas
        Aug 15 at 7:09















      5
















      I found that it didn't limit the search to only text files




      ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files (determined using heuristics based on file name and content) and will by default skip directories like .git/.svn which if you're a developer is likely what you want. https://beyondgrep.com/.



      It's packed by most GNU/Linux distros so it's easy to install. It's written in perl (so its regexps are perl regexps, similar to those of GNU grep -P).



      ack -- "desired text" $(<subdirs.txt)


      should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.



      (Different ways of word-splitting subdirs.txt onto a command line are covered in other answers. You might want to just let the shell's standard word-splitting do it, or readarray to split only on lines and also block glob expansion.)






      share|improve this answer



























      • Not the it only properly works with ASCII/ISO8859-1 data (not non-ASCII UTF-8 characters, even with PERL_UNICODE=SLAD which seems to only work for its --filter)

        – Stéphane Chazelas
        Aug 15 at 6:50






      • 1





        PERLIO=':utf8' PERL_UNICODE=A ack 'utf8 text' helps (though makes it significantly slower and reports decoding errors for non-UTF-8 input).

        – Stéphane Chazelas
        Aug 15 at 7:09













      5














      5










      5










      I found that it didn't limit the search to only text files




      ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files (determined using heuristics based on file name and content) and will by default skip directories like .git/.svn which if you're a developer is likely what you want. https://beyondgrep.com/.



      It's packed by most GNU/Linux distros so it's easy to install. It's written in perl (so its regexps are perl regexps, similar to those of GNU grep -P).



      ack -- "desired text" $(<subdirs.txt)


      should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.



      (Different ways of word-splitting subdirs.txt onto a command line are covered in other answers. You might want to just let the shell's standard word-splitting do it, or readarray to split only on lines and also block glob expansion.)






      share|improve this answer
















      I found that it didn't limit the search to only text files




      ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files (determined using heuristics based on file name and content) and will by default skip directories like .git/.svn which if you're a developer is likely what you want. https://beyondgrep.com/.



      It's packed by most GNU/Linux distros so it's easy to install. It's written in perl (so its regexps are perl regexps, similar to those of GNU grep -P).



      ack -- "desired text" $(<subdirs.txt)


      should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.



      (Different ways of word-splitting subdirs.txt onto a command line are covered in other answers. You might want to just let the shell's standard word-splitting do it, or readarray to split only on lines and also block glob expansion.)







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Aug 15 at 6:49









      Stéphane Chazelas

      331k58 gold badges648 silver badges1017 bronze badges




      331k58 gold badges648 silver badges1017 bronze badges










      answered Aug 15 at 5:38









      Peter CordesPeter Cordes

      4,73016 silver badges35 bronze badges




      4,73016 silver badges35 bronze badges















      • Not the it only properly works with ASCII/ISO8859-1 data (not non-ASCII UTF-8 characters, even with PERL_UNICODE=SLAD which seems to only work for its --filter)

        – Stéphane Chazelas
        Aug 15 at 6:50






      • 1





        PERLIO=':utf8' PERL_UNICODE=A ack 'utf8 text' helps (though makes it significantly slower and reports decoding errors for non-UTF-8 input).

        – Stéphane Chazelas
        Aug 15 at 7:09

















      • Not the it only properly works with ASCII/ISO8859-1 data (not non-ASCII UTF-8 characters, even with PERL_UNICODE=SLAD which seems to only work for its --filter)

        – Stéphane Chazelas
        Aug 15 at 6:50






      • 1





        PERLIO=':utf8' PERL_UNICODE=A ack 'utf8 text' helps (though makes it significantly slower and reports decoding errors for non-UTF-8 input).

        – Stéphane Chazelas
        Aug 15 at 7:09
















      Not the it only properly works with ASCII/ISO8859-1 data (not non-ASCII UTF-8 characters, even with PERL_UNICODE=SLAD which seems to only work for its --filter)

      – Stéphane Chazelas
      Aug 15 at 6:50





      Not the it only properly works with ASCII/ISO8859-1 data (not non-ASCII UTF-8 characters, even with PERL_UNICODE=SLAD which seems to only work for its --filter)

      – Stéphane Chazelas
      Aug 15 at 6:50




      1




      1





      PERLIO=':utf8' PERL_UNICODE=A ack 'utf8 text' helps (though makes it significantly slower and reports decoding errors for non-UTF-8 input).

      – Stéphane Chazelas
      Aug 15 at 7:09





      PERLIO=':utf8' PERL_UNICODE=A ack 'utf8 text' helps (though makes it significantly slower and reports decoding errors for non-UTF-8 input).

      – Stéphane Chazelas
      Aug 15 at 7:09











      5















      Naturally, posting the question helped snap me out of my fixation on doing this strictly with find and made me think of expanding the file via Bash. I'm posting an answer hoping it will help someone else (and also to document this for my own future use).



      The incantation for having Bash expand the file contents is $(<subdirs2search.txt). So, if subdirs2search.txt contains:



      SubDir1 SubDir2 SubDir4


      A command like the following will accomplish the desired search:



      find $(<subdirs2search.txt) -type f -name="*.txt" -exec grep -H "desired text" ;





      share|improve this answer



























      • Note that it's not specific to bash. The $(<file) operator comes from ksh and is also supported by zsh. In other POSIX-like shells, you can use $(cat file) instead.

        – Stéphane Chazelas
        Aug 14 at 21:02












      • @StéphaneChazelas: Thanks for the input. That said, I've rolled back to my original answer. Testing your solution, I found that it didn't limit the search to only text files, and it ran significantly slower. Also, it is different enough that - IMO - you should submit it as your own answer.

        – GreenMatt
        Aug 14 at 21:20






      • 1





        "I found that it didn't limit the search to only text files", to be fair, neither does your find command.

        – muru
        Aug 15 at 5:30






      • 2





        @muru and Matt: ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files. beyondgrep.com. It's packed by most GNU/Linux distros. e.g. ack "desired text" $(<subdirs.txt) should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.

        – Peter Cordes
        Aug 15 at 5:36






      • 1





        With grep, that's --include='*.txt'

        – muru
        Aug 15 at 15:46















      5















      Naturally, posting the question helped snap me out of my fixation on doing this strictly with find and made me think of expanding the file via Bash. I'm posting an answer hoping it will help someone else (and also to document this for my own future use).



      The incantation for having Bash expand the file contents is $(<subdirs2search.txt). So, if subdirs2search.txt contains:



      SubDir1 SubDir2 SubDir4


      A command like the following will accomplish the desired search:



      find $(<subdirs2search.txt) -type f -name="*.txt" -exec grep -H "desired text" ;





      share|improve this answer



























      • Note that it's not specific to bash. The $(<file) operator comes from ksh and is also supported by zsh. In other POSIX-like shells, you can use $(cat file) instead.

        – Stéphane Chazelas
        Aug 14 at 21:02












      • @StéphaneChazelas: Thanks for the input. That said, I've rolled back to my original answer. Testing your solution, I found that it didn't limit the search to only text files, and it ran significantly slower. Also, it is different enough that - IMO - you should submit it as your own answer.

        – GreenMatt
        Aug 14 at 21:20






      • 1





        "I found that it didn't limit the search to only text files", to be fair, neither does your find command.

        – muru
        Aug 15 at 5:30






      • 2





        @muru and Matt: ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files. beyondgrep.com. It's packed by most GNU/Linux distros. e.g. ack "desired text" $(<subdirs.txt) should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.

        – Peter Cordes
        Aug 15 at 5:36






      • 1





        With grep, that's --include='*.txt'

        – muru
        Aug 15 at 15:46













      5














      5










      5









      Naturally, posting the question helped snap me out of my fixation on doing this strictly with find and made me think of expanding the file via Bash. I'm posting an answer hoping it will help someone else (and also to document this for my own future use).



      The incantation for having Bash expand the file contents is $(<subdirs2search.txt). So, if subdirs2search.txt contains:



      SubDir1 SubDir2 SubDir4


      A command like the following will accomplish the desired search:



      find $(<subdirs2search.txt) -type f -name="*.txt" -exec grep -H "desired text" ;





      share|improve this answer















      Naturally, posting the question helped snap me out of my fixation on doing this strictly with find and made me think of expanding the file via Bash. I'm posting an answer hoping it will help someone else (and also to document this for my own future use).



      The incantation for having Bash expand the file contents is $(<subdirs2search.txt). So, if subdirs2search.txt contains:



      SubDir1 SubDir2 SubDir4


      A command like the following will accomplish the desired search:



      find $(<subdirs2search.txt) -type f -name="*.txt" -exec grep -H "desired text" ;






      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Aug 15 at 15:43

























      answered Aug 14 at 20:09









      GreenMattGreenMatt

      4154 silver badges14 bronze badges




      4154 silver badges14 bronze badges















      • Note that it's not specific to bash. The $(<file) operator comes from ksh and is also supported by zsh. In other POSIX-like shells, you can use $(cat file) instead.

        – Stéphane Chazelas
        Aug 14 at 21:02












      • @StéphaneChazelas: Thanks for the input. That said, I've rolled back to my original answer. Testing your solution, I found that it didn't limit the search to only text files, and it ran significantly slower. Also, it is different enough that - IMO - you should submit it as your own answer.

        – GreenMatt
        Aug 14 at 21:20






      • 1





        "I found that it didn't limit the search to only text files", to be fair, neither does your find command.

        – muru
        Aug 15 at 5:30






      • 2





        @muru and Matt: ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files. beyondgrep.com. It's packed by most GNU/Linux distros. e.g. ack "desired text" $(<subdirs.txt) should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.

        – Peter Cordes
        Aug 15 at 5:36






      • 1





        With grep, that's --include='*.txt'

        – muru
        Aug 15 at 15:46

















      • Note that it's not specific to bash. The $(<file) operator comes from ksh and is also supported by zsh. In other POSIX-like shells, you can use $(cat file) instead.

        – Stéphane Chazelas
        Aug 14 at 21:02












      • @StéphaneChazelas: Thanks for the input. That said, I've rolled back to my original answer. Testing your solution, I found that it didn't limit the search to only text files, and it ran significantly slower. Also, it is different enough that - IMO - you should submit it as your own answer.

        – GreenMatt
        Aug 14 at 21:20






      • 1





        "I found that it didn't limit the search to only text files", to be fair, neither does your find command.

        – muru
        Aug 15 at 5:30






      • 2





        @muru and Matt: ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files. beyondgrep.com. It's packed by most GNU/Linux distros. e.g. ack "desired text" $(<subdirs.txt) should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.

        – Peter Cordes
        Aug 15 at 5:36






      • 1





        With grep, that's --include='*.txt'

        – muru
        Aug 15 at 15:46
















      Note that it's not specific to bash. The $(<file) operator comes from ksh and is also supported by zsh. In other POSIX-like shells, you can use $(cat file) instead.

      – Stéphane Chazelas
      Aug 14 at 21:02






      Note that it's not specific to bash. The $(<file) operator comes from ksh and is also supported by zsh. In other POSIX-like shells, you can use $(cat file) instead.

      – Stéphane Chazelas
      Aug 14 at 21:02














      @StéphaneChazelas: Thanks for the input. That said, I've rolled back to my original answer. Testing your solution, I found that it didn't limit the search to only text files, and it ran significantly slower. Also, it is different enough that - IMO - you should submit it as your own answer.

      – GreenMatt
      Aug 14 at 21:20





      @StéphaneChazelas: Thanks for the input. That said, I've rolled back to my original answer. Testing your solution, I found that it didn't limit the search to only text files, and it ran significantly slower. Also, it is different enough that - IMO - you should submit it as your own answer.

      – GreenMatt
      Aug 14 at 21:20




      1




      1





      "I found that it didn't limit the search to only text files", to be fair, neither does your find command.

      – muru
      Aug 15 at 5:30





      "I found that it didn't limit the search to only text files", to be fair, neither does your find command.

      – muru
      Aug 15 at 5:30




      2




      2





      @muru and Matt: ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files. beyondgrep.com. It's packed by most GNU/Linux distros. e.g. ack "desired text" $(<subdirs.txt) should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.

      – Peter Cordes
      Aug 15 at 5:36





      @muru and Matt: ack is often a handy tool for recursive-grep type stuff. It does by default limit searching to text files. beyondgrep.com. It's packed by most GNU/Linux distros. e.g. ack "desired text" $(<subdirs.txt) should probably do what you want and is very easy to type. Plus it does nice color output for interactive use.

      – Peter Cordes
      Aug 15 at 5:36




      1




      1





      With grep, that's --include='*.txt'

      – muru
      Aug 15 at 15:46





      With grep, that's --include='*.txt'

      – muru
      Aug 15 at 15:46











      3















      Another tool similar to ack (Peter Cordes's answer) is ripgrep or rg. It supports the same usage:



      rg -- "desired text" $(<subdirs2search.txt)


      It also skips binary files by default.






      share|improve this answer





























        3















        Another tool similar to ack (Peter Cordes's answer) is ripgrep or rg. It supports the same usage:



        rg -- "desired text" $(<subdirs2search.txt)


        It also skips binary files by default.






        share|improve this answer



























          3














          3










          3









          Another tool similar to ack (Peter Cordes's answer) is ripgrep or rg. It supports the same usage:



          rg -- "desired text" $(<subdirs2search.txt)


          It also skips binary files by default.






          share|improve this answer













          Another tool similar to ack (Peter Cordes's answer) is ripgrep or rg. It supports the same usage:



          rg -- "desired text" $(<subdirs2search.txt)


          It also skips binary files by default.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Aug 15 at 13:27









          Mark AndersonMark Anderson

          311 bronze badge




          311 bronze badge
























              3

















              #!/usr/bin/perl -w

              use strict;
              use File::Find ();

              sub wanted;
              sub process_file ($@);

              my $dirfile = shift; # First argument is the filename containing the list
              # of directories.

              my $pattern = shift; # Second arg is a perl RE containing the pattern to search
              # for. Remember to single-quote it on the command line.

              # Read in the @dirs array from $dirfile
              #
              # A NUL-separated file is best, just in case any of the directory names
              # contained line-feeds. If you're certain that could never happen, a
              # plain-text LF-separated file would do.
              #
              # BTW, you can easily generate a NUL-separated file from the shell with:
              # printf "%s" dir1 dir2 dir3 dir4 $'dirnwithn3nLFs' > dirs.txt

              my @dirs=();


              local $/=""; # delete this line if you want to use a LF-separated file.
              # In that case, the ... block around the code from open to
              # close is no longer needed. It's only there so it's possible
              # to make a local change to the $/ aka $INPUT_RECORD_SEPARATOR
              # variable.

              open(DIRFILE,"<",$dirfile);
              while(<DIRFILE>)
              chomp;
              push @dirs, $_;
              ;
              close(DIRFILE);
              ;

              File::Find::find(wanted => &wanted, @dirs);
              exit;

              sub wanted
              my ($dev,$ino,$mode,$nlink,$uid,$gid);

              (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && -f _ && process_file($_);


              sub process_file ($@)

              # This function currently just greps for pattern in the filename passed to
              # it. As the function name implies, it could be used to process the file
              # in any way, not just grep it.

              my $filename = shift;

              # uncomment the return statement below to skip "binary" files.
              # (note this is a workable but fairly crude test. Perl's File::MMagic
              # module can be used to more accurately identify file types, using the
              # same "magic" file databases as the /usr/bin/file command)

              # return if -B $filename;

              open(FILE,"<",$filename);
              while(<FILE>)
              print "$filename:$_" if (m/$pattern/o) ;
              ;

              close(FILE);



              This uses perl and perl's File::Find module to do the same thing as your find ... -exec grep.



              There's nothing particularly interesting or special about this script except that the process_file function can be very easily modified to do anything you want with or to the file - e.g. change owner or perms, delete it, rename it, insert or delete lines or whatever else you might want.



              e.g. if you wanted to delete files which contain text matching the pattern, you could replace the process_file function with something like this:



              sub process_file ($@) 

              my $filename = shift;
              my $found = 0;

              # uncomment to skip "binary" files:
              return if -B $filename;

              open(FILE,"<",$filename);
              while(<FILE>)
              if (m/$pattern/o)
              $found = 1;
              last;
              ;
              ;

              close(FILE);
              unlink $filename if ($found);



              It's also worth mentioning that the wanted function in this script is currently only looking for regular files (the -f test). Perl's stat and lstat functions provide access to all of the file metadata that find can use to match files (uid, gid, perms, size, atime, mtime, etc) so the wanted function can replicate ANY and all find predicates. see perldoc -f stat and perldoc -f lstat for details.



              BTW, the script was generated initially by find2perl, and then modified substantially to a) read in the list of directories from a file, and b) to do the grep in perl code rather than by forking grep and c) add a lot of comments. Performance should be nearly identical to find ... -exec grep because grep can't open files or do a regexp pattern match significantly faster than perl can. It may even be faster.



              Also BTW, find2perl used to be included with perl, but since perl 5.22 it was removed and can now be found on CPAN at find2perl






              share|improve this answer































                3

















                #!/usr/bin/perl -w

                use strict;
                use File::Find ();

                sub wanted;
                sub process_file ($@);

                my $dirfile = shift; # First argument is the filename containing the list
                # of directories.

                my $pattern = shift; # Second arg is a perl RE containing the pattern to search
                # for. Remember to single-quote it on the command line.

                # Read in the @dirs array from $dirfile
                #
                # A NUL-separated file is best, just in case any of the directory names
                # contained line-feeds. If you're certain that could never happen, a
                # plain-text LF-separated file would do.
                #
                # BTW, you can easily generate a NUL-separated file from the shell with:
                # printf "%s" dir1 dir2 dir3 dir4 $'dirnwithn3nLFs' > dirs.txt

                my @dirs=();


                local $/=""; # delete this line if you want to use a LF-separated file.
                # In that case, the ... block around the code from open to
                # close is no longer needed. It's only there so it's possible
                # to make a local change to the $/ aka $INPUT_RECORD_SEPARATOR
                # variable.

                open(DIRFILE,"<",$dirfile);
                while(<DIRFILE>)
                chomp;
                push @dirs, $_;
                ;
                close(DIRFILE);
                ;

                File::Find::find(wanted => &wanted, @dirs);
                exit;

                sub wanted
                my ($dev,$ino,$mode,$nlink,$uid,$gid);

                (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && -f _ && process_file($_);


                sub process_file ($@)

                # This function currently just greps for pattern in the filename passed to
                # it. As the function name implies, it could be used to process the file
                # in any way, not just grep it.

                my $filename = shift;

                # uncomment the return statement below to skip "binary" files.
                # (note this is a workable but fairly crude test. Perl's File::MMagic
                # module can be used to more accurately identify file types, using the
                # same "magic" file databases as the /usr/bin/file command)

                # return if -B $filename;

                open(FILE,"<",$filename);
                while(<FILE>)
                print "$filename:$_" if (m/$pattern/o) ;
                ;

                close(FILE);



                This uses perl and perl's File::Find module to do the same thing as your find ... -exec grep.



                There's nothing particularly interesting or special about this script except that the process_file function can be very easily modified to do anything you want with or to the file - e.g. change owner or perms, delete it, rename it, insert or delete lines or whatever else you might want.



                e.g. if you wanted to delete files which contain text matching the pattern, you could replace the process_file function with something like this:



                sub process_file ($@) 

                my $filename = shift;
                my $found = 0;

                # uncomment to skip "binary" files:
                return if -B $filename;

                open(FILE,"<",$filename);
                while(<FILE>)
                if (m/$pattern/o)
                $found = 1;
                last;
                ;
                ;

                close(FILE);
                unlink $filename if ($found);



                It's also worth mentioning that the wanted function in this script is currently only looking for regular files (the -f test). Perl's stat and lstat functions provide access to all of the file metadata that find can use to match files (uid, gid, perms, size, atime, mtime, etc) so the wanted function can replicate ANY and all find predicates. see perldoc -f stat and perldoc -f lstat for details.



                BTW, the script was generated initially by find2perl, and then modified substantially to a) read in the list of directories from a file, and b) to do the grep in perl code rather than by forking grep and c) add a lot of comments. Performance should be nearly identical to find ... -exec grep because grep can't open files or do a regexp pattern match significantly faster than perl can. It may even be faster.



                Also BTW, find2perl used to be included with perl, but since perl 5.22 it was removed and can now be found on CPAN at find2perl






                share|improve this answer





























                  3














                  3










                  3











                  #!/usr/bin/perl -w

                  use strict;
                  use File::Find ();

                  sub wanted;
                  sub process_file ($@);

                  my $dirfile = shift; # First argument is the filename containing the list
                  # of directories.

                  my $pattern = shift; # Second arg is a perl RE containing the pattern to search
                  # for. Remember to single-quote it on the command line.

                  # Read in the @dirs array from $dirfile
                  #
                  # A NUL-separated file is best, just in case any of the directory names
                  # contained line-feeds. If you're certain that could never happen, a
                  # plain-text LF-separated file would do.
                  #
                  # BTW, you can easily generate a NUL-separated file from the shell with:
                  # printf "%s" dir1 dir2 dir3 dir4 $'dirnwithn3nLFs' > dirs.txt

                  my @dirs=();


                  local $/=""; # delete this line if you want to use a LF-separated file.
                  # In that case, the ... block around the code from open to
                  # close is no longer needed. It's only there so it's possible
                  # to make a local change to the $/ aka $INPUT_RECORD_SEPARATOR
                  # variable.

                  open(DIRFILE,"<",$dirfile);
                  while(<DIRFILE>)
                  chomp;
                  push @dirs, $_;
                  ;
                  close(DIRFILE);
                  ;

                  File::Find::find(wanted => &wanted, @dirs);
                  exit;

                  sub wanted
                  my ($dev,$ino,$mode,$nlink,$uid,$gid);

                  (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && -f _ && process_file($_);


                  sub process_file ($@)

                  # This function currently just greps for pattern in the filename passed to
                  # it. As the function name implies, it could be used to process the file
                  # in any way, not just grep it.

                  my $filename = shift;

                  # uncomment the return statement below to skip "binary" files.
                  # (note this is a workable but fairly crude test. Perl's File::MMagic
                  # module can be used to more accurately identify file types, using the
                  # same "magic" file databases as the /usr/bin/file command)

                  # return if -B $filename;

                  open(FILE,"<",$filename);
                  while(<FILE>)
                  print "$filename:$_" if (m/$pattern/o) ;
                  ;

                  close(FILE);



                  This uses perl and perl's File::Find module to do the same thing as your find ... -exec grep.



                  There's nothing particularly interesting or special about this script except that the process_file function can be very easily modified to do anything you want with or to the file - e.g. change owner or perms, delete it, rename it, insert or delete lines or whatever else you might want.



                  e.g. if you wanted to delete files which contain text matching the pattern, you could replace the process_file function with something like this:



                  sub process_file ($@) 

                  my $filename = shift;
                  my $found = 0;

                  # uncomment to skip "binary" files:
                  return if -B $filename;

                  open(FILE,"<",$filename);
                  while(<FILE>)
                  if (m/$pattern/o)
                  $found = 1;
                  last;
                  ;
                  ;

                  close(FILE);
                  unlink $filename if ($found);



                  It's also worth mentioning that the wanted function in this script is currently only looking for regular files (the -f test). Perl's stat and lstat functions provide access to all of the file metadata that find can use to match files (uid, gid, perms, size, atime, mtime, etc) so the wanted function can replicate ANY and all find predicates. see perldoc -f stat and perldoc -f lstat for details.



                  BTW, the script was generated initially by find2perl, and then modified substantially to a) read in the list of directories from a file, and b) to do the grep in perl code rather than by forking grep and c) add a lot of comments. Performance should be nearly identical to find ... -exec grep because grep can't open files or do a regexp pattern match significantly faster than perl can. It may even be faster.



                  Also BTW, find2perl used to be included with perl, but since perl 5.22 it was removed and can now be found on CPAN at find2perl






                  share|improve this answer

















                  #!/usr/bin/perl -w

                  use strict;
                  use File::Find ();

                  sub wanted;
                  sub process_file ($@);

                  my $dirfile = shift; # First argument is the filename containing the list
                  # of directories.

                  my $pattern = shift; # Second arg is a perl RE containing the pattern to search
                  # for. Remember to single-quote it on the command line.

                  # Read in the @dirs array from $dirfile
                  #
                  # A NUL-separated file is best, just in case any of the directory names
                  # contained line-feeds. If you're certain that could never happen, a
                  # plain-text LF-separated file would do.
                  #
                  # BTW, you can easily generate a NUL-separated file from the shell with:
                  # printf "%s" dir1 dir2 dir3 dir4 $'dirnwithn3nLFs' > dirs.txt

                  my @dirs=();


                  local $/=""; # delete this line if you want to use a LF-separated file.
                  # In that case, the ... block around the code from open to
                  # close is no longer needed. It's only there so it's possible
                  # to make a local change to the $/ aka $INPUT_RECORD_SEPARATOR
                  # variable.

                  open(DIRFILE,"<",$dirfile);
                  while(<DIRFILE>)
                  chomp;
                  push @dirs, $_;
                  ;
                  close(DIRFILE);
                  ;

                  File::Find::find(wanted => &wanted, @dirs);
                  exit;

                  sub wanted
                  my ($dev,$ino,$mode,$nlink,$uid,$gid);

                  (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && -f _ && process_file($_);


                  sub process_file ($@)

                  # This function currently just greps for pattern in the filename passed to
                  # it. As the function name implies, it could be used to process the file
                  # in any way, not just grep it.

                  my $filename = shift;

                  # uncomment the return statement below to skip "binary" files.
                  # (note this is a workable but fairly crude test. Perl's File::MMagic
                  # module can be used to more accurately identify file types, using the
                  # same "magic" file databases as the /usr/bin/file command)

                  # return if -B $filename;

                  open(FILE,"<",$filename);
                  while(<FILE>)
                  print "$filename:$_" if (m/$pattern/o) ;
                  ;

                  close(FILE);



                  This uses perl and perl's File::Find module to do the same thing as your find ... -exec grep.



                  There's nothing particularly interesting or special about this script except that the process_file function can be very easily modified to do anything you want with or to the file - e.g. change owner or perms, delete it, rename it, insert or delete lines or whatever else you might want.



                  e.g. if you wanted to delete files which contain text matching the pattern, you could replace the process_file function with something like this:



                  sub process_file ($@) 

                  my $filename = shift;
                  my $found = 0;

                  # uncomment to skip "binary" files:
                  return if -B $filename;

                  open(FILE,"<",$filename);
                  while(<FILE>)
                  if (m/$pattern/o)
                  $found = 1;
                  last;
                  ;
                  ;

                  close(FILE);
                  unlink $filename if ($found);



                  It's also worth mentioning that the wanted function in this script is currently only looking for regular files (the -f test). Perl's stat and lstat functions provide access to all of the file metadata that find can use to match files (uid, gid, perms, size, atime, mtime, etc) so the wanted function can replicate ANY and all find predicates. see perldoc -f stat and perldoc -f lstat for details.



                  BTW, the script was generated initially by find2perl, and then modified substantially to a) read in the list of directories from a file, and b) to do the grep in perl code rather than by forking grep and c) add a lot of comments. Performance should be nearly identical to find ... -exec grep because grep can't open files or do a regexp pattern match significantly faster than perl can. It may even be faster.



                  Also BTW, find2perl used to be included with perl, but since perl 5.22 it was removed and can now be found on CPAN at find2perl







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Aug 17 at 2:03

























                  answered Aug 15 at 4:47









                  cascas

                  42.1k4 gold badges62 silver badges112 bronze badges




                  42.1k4 gold badges62 silver badges112 bronze badges






























                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Unix & Linux Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f535634%2fhow-can-i-find-files-in-directories-listed-in-a-file%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Grendel Contents Story Scholarship Depictions Notes References Navigation menu10.1093/notesj/gjn112Berserkeree

                      Area configuration aggregation error after install Porto themeMagento 2.1 CE Installed but front/backend not loading/workingCSS not loading on page within Magento 2 pageCannot install module in Magento 2no commands defined in the “setup” namespace. in Magento2Magento 2: Static files are present but shows 404Why do i have to always run the commands to clean cache in Magento 2.1.8?Failure reason: 'Unable to unserialize value.'Error 500 after magento migrationIn production mode the site does not loadMagento 2 : Error 500 after installing

                      Middle Expansion Olielle Resaix Definition: Uttering songs of triumph shouting with joy triumphant exulting Sejunction Journal 붙다 달 고급 품목 외출 The stretch trades the screeching tin. Definition: The act of speaking with a drawl a drawl Cough Sand Definition: An uproar a quarrel a noisy outbreak Shake Iron Publicize Horse House Baby 사과 Resaix Flaggy Jelly Temporary Unequaled Puppet A drop in the bucket Shrew 성격 회원 성질 미팅 The burn frames the tacky quality. Materialistic The smoke reduces the way. Yammoe Nondescript Cheek 얼굴 배 약하다 날리다 타다 The illegal country shows the iron. Help Rule Drearien Smoke Teaching Meaty Wasp Abraham Lincoln Jaws 진심 수리하다 Size Cork Idea Convert Think Lark John Lennon 거울 청소 군 추천하다 아이스크림