47

Is there any way to tell ack to only search for text on the current folder? (or specify a max-depth level?) And with grep?

1
  • 1
    No, ack does not have a max-depth option, other than the -n to not recurse at all. Apr 24 '14 at 14:41
48

You can couple find with the -exec argument. Example:

find . -maxdepth 1 -exec grep foo {} \;

This can be scaled, i.e. -maxdepth 2.

Edit

As mentioned in the [answer by @Stéphane Chazelas], it is advisable to restrict find to regular files so that grep doesn't produce an error when the argument {} actually is a directory path:

find . -maxdepth 1 -type f -exec grep -H foo {} \;
  • -type f is a filter for find that limits the search results to files
  • -H is a grep option used to print a filename for every match (desired behavior when more than one file match)
7
  • 1
    Stephane, my answer (-maxdepth 1) was scaleable. For example -maxdepth 2. I do not know how to describe the edit you made as such. Jan 30 '14 at 20:15
  • 6
    Yes sorry, I agree my edit was too much intrusive. You may still want to clarify that that (-maxdepth) is not portable/standard syntax (only GNU and some BSDs). Also, there's no point using \; here (run one grep per file). Use grep -H foo {} + (GNU specific) or grep foo /dev/null {} + (standard) to make sure the file name is always printed. The standard equivalent to -maxdepth 2 would be find . -path './*/*' -type d -prune -o -type f -exec ... Jan 31 '14 at 6:57
  • 4
    Also note that yours will give error messages for directories (including . as you don't give the -mindepth 1) while GNU grep will not try to read directories with -r (it recurses on them). You may want to add a -d skip to grep (assuming GNU grep) or better add ! -type d to find or even better -type f (or -xtype f assuming GNU find) as you probably don't want grep to read non-regular files. Jan 31 '14 at 7:01
  • 5
    I tend to use grep -Hin with this approach so that I can see the filename and the line that the occurrence is on.
    – GDP2
    Apr 11 '16 at 19:41
  • 1
    @uav feel free to send a patch to the GNU utils mailing list. The idea behind GNU tools is that each tool should have a limited, specialized set of features and be used in cooperation. GNU find has all the features you need to drill down a file system, filtering out anything you don't want. Embedding it within grep, sed and gawk seems like a lot of redundant effort.
    – sleblanc
    Nov 2 '20 at 13:39
28

Use -n for no-recurse:

$ ack -n foo

grep is not recursive by default, and you should use the -r flag only if you want a recursive search.

You can search the current directory with grep as follows:

$ grep -- foo *
5
  • 25
    Doesn't answer the question? (what if I want to recurse to a depth of 2)
    – Steven Lu
    Aug 25 '15 at 17:13
  • Good point, I missed that. Any suggestions? Aug 25 '15 at 21:33
  • @StevenLu, you can recurse a number of directories by using globs: ack -n pattern */*/. It has several caveats, like expanding directories with an extreme number of subdirectories. If you make sure that the glob has a slash at the end, then it will only expand directory names, so that should limit the potential for damage, a bit.
    – sleblanc
    Nov 2 '20 at 13:48
  • Cool. FWIW I don't use ack anymore, ripgrep is where it's at.
    – Steven Lu
    Nov 2 '20 at 20:38
  • where can I find clarification for the syntax 'grep --'? I didn't find it it 'man grep'. Sep 8 at 7:20
2

For an equivalent of GNU grep -r foo . that looks only in regular files in the current directory and not any of the subdirectories, you can do:

  • zsh and GNU grep or compatible:

    grep -H foo ./*(.D)
    
  • standard find and grep from any shell:

    find . ! -name . -prune -type f -exec grep foo /dev/null {} +
    
  • GNU find and GNU grep (or compatible) from any shell:

    find . -maxdepth 1 -type f -exec grep -H foo {} +
    

To look for files at depths 1 to 3 (in ./file, ./subdir/file, ./subdir/subsubdir/file, but not any deeper):

  • GNU find and GNU grep (or compatible) from any shell:

    find . -maxdepth 3 -type f -exec grep -H foo {} +
    
  • standard find and grep, but assuming file names are valid text in the locale:

    find . '(' ! -path './*/*/*' -o -prune ')' -o -exec grep foo /dev/null {} +
    
  • zsh and GNU grep or compatible:

    set -o extendedglob # best in ~/.zshrc
    grep -H foo ./**/*~./*/*/*/*(D.)
    

    though note that it's inefficient as it still looks for files at any depth before excluding them with the ~ extendedglob operator.

-H (GNU extension) / /dev/null is to make sure grep prints the name of the file even if only one file is given to it.

-type f or zsh's . glob qualifier is to select only regular files (like GNU grep does by default with -r nowadays), to the exclusion of all other types of files such as symlinks (even if they point to regular files), directories, fifos, devices...

1

I'm obviously late to the topic, but this may prove useful to a future reader. After reading the comments and answers above, perhaps a wrapper script for grep is in order until GNU find gains a -maxdepth option. Using a pattern like the following,

 grep -Hin foo `find . -maxdepth 1 -type f`

the following script will effectively wrap the pair of commands:

#! /bin/sh
#
# USAGE: grep-maxdepth <NUM> <GREP_ARGS>
#
#    <NUM>        integer specifying the maxdepth passed to find
#    <GREP_ARGS>  arguments provided to grep
#
depth=$1
shift
# DON'T DO THIS ! grep $* `find . -maxdepth ${depth} -type f`
# DO this based upon comments
find . -maxdepth ${depth} -type f -exec grep $* {} \;

This solution should work regardless of the availability of GNU grep; however, the usage of -maxdepth for find implies the installation of GNU's Tools.

I don't use ack, but this simple solution should work for it as well.

NOTE: Trivially-edited based upon comment from Stéphane Chazelas. This should now properly-accommodate white space and other characters in file names. Thanks.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.