Hacker News new | ask | show | jobs
ffind: a sane replacement for command line file search (wrongsideofmemphis.com)
52 points by molbon 4752 days ago
15 comments

I wrote a similar tool to this in C, ff (https://github.com/silentbicycle/ff).

The main difference is that, where `ffind foo` appears to be comparable to

    find . -name "*foo*"
, ff is closer to

    find . -name ".*f.*o.*o.*"
In other words, you don't need an exact match, just the characters given in order. (This is inspired by Lisp-y toolchains where e.g. c-w-c-c would search and expand to call-with-current-continuation.)

There are some other features (e.g. '=' toggles literal match, it has smart handling for '/' and directory name grouping), but it's pretty straightforward to use. It also doesn't depend on python.

Similarly, I have a little shell function loaded by .zshrc that covers 90% of my use cases:

   findit() {
       find . -name \* -exec grep -iH $1 {} \;
   }
Why not just run a recursive grep? That would save having to invoke grep on every single file found.

    findit() {
        grep -iHR $1 .
    }
Alternately, you could use the '+' variant of -exec in order to batch files together to be processed together.
Cool, I wasn't aware of a -R flag in grep for some reason. I need to go back and re-read the man pages...
Right. There's no need to write a whole new tool just to simplify invocation for common cases. For a guy who uses the command line "a LOT" he's not making good use of his shell.
Is this not equivalent and avoids running grep(1) once for each path?

    find -exec grep -iH ${1?} {} +
Though it still runs grep on directories.
Author possibly meant something like this (but yeah, same idea) fffind () { find . -regex ".$1."; }
Many of the commenters here have missed an essential line of ffind's description from the article, emphasis mine:

> find in this directory and all the subdirectories a file that contains some_text in its filename

This is NOT a find+grep/ack/ag -alike. It's used for rapid search on filenames, not file contents. Think of it as TextMate's Cmd-T for the command-line.

I find myself doing this a lot when sifting through huge codebases:

find . -type f -print0 | xargs -0 grep -Hin <identifier>

The -print0/xargs thing is to get around spaces in filenames or directories. I don't think spaces belong in source files (or directory trees containing source code) for a gazillion different reasons, but I still stumble across it every once in a great while. There are also platforms where system directories have spaces in them, so if you're scrounging through a deep subdirectory tree trying to find something, you may have to deal with the spaces thing. I've been bitten by it enough times that I just always do this rather than have to think about whether or not I might need to do it every time I use find.

Depending on what I'm looking for, I might select files with -type, or a -name glob, or whatever. I use '-type f' most commonly because the source code I deal with has a fair number of interesting things defined outside of files with the standard source/header extensions in their names.

There's usually a couple pipe stages after this filled with 'grep -v <stuff I don't care about>', or more greps to narrow down the result set. Sometimes this all goes in shell scripts or sometimes I just type it all out.

How about

  grep -irn <identifier> .
?

-r recurses and since it is multiple files implies -H.

Yep, that's much nicer. :) I always forget about recursive grep.
Alternatively, you may just install locate. It won't examine file contents, but it works in the common cases. It's also blazingly fast because it's indexed.
Its problem that you always have to update the index, which can be problematic in fast changing systems (and quite slow in some cases). The greatest disadvantage is that you need root rights to update the index.
You can have arbitrary indices being created by arbitrary users. The database(s) that is(are) used by the locate command can be specified by command-line option or by an environment variable.
If you just want a shortcut to invoke find in this common way, put this in your shell's profile:

  function ffind {
      if [ $# -eq 1 ]; then
          search_path='.'
          expression=$1
      elif [ $# -eq 2 ]; then
          search_path=$1
          expression=$2
      else
          echo "ffind [path] expression"
          return 1
      fi
      find $search_path -name $expression
}
I looked into his python implementation, I thought he would just translate the parameters and call find, but he instead did go to implement the search algorithm. Wouldn't that make it a bit slower than the original find?
File system traversal can be quite slow on traditional hard disk drive, it requires a lot of random disk access which has much higher latency than sequential access (think about the moving parts in the disk drive). So I guess that being written in Python is hardly the bottleneck if the disk reads have not been cached by the kernel.
What are the advantages of this over

    mdfind -onlyin . <str>
The author probably wanted a simple command, that required as few parameters as needed.
It searches the contents of files, not just the names of files.
So does mdfind.
I stand corrected.

(I tested before I posted, but forgot MD indexing was turned off.)

Yeah thats ok but holy cow, thanks for letting me find out about ack! ack is awesome!
If you like ack (and who doesn't???), you might like more or less `ag`: https://github.com/ggreer/the_silver_searcher
I did notice ack is pretty slow and i may try ag but speed isnt a problem here for me i think

btw, heres what ive been using up until now:

    alias gerp='grep -riHnT . -e'
and more recently:

    alias gerp="find . -type f | perl -lne 'print if -T;' | xargs egrep -riHnT"
ag is great - so much faster than Ack.
Try grin if you're biased in favor of Python: https://pypi.python.org/pypi/grin
This ffind isn't this ffind: https://github.com/sjl/friendly-find ?
In zsh:

    print -l **/*myfile
From reading this, I'm not entirely sure what makes this better than grep. I get why it is cool to have written it.
It's not a replacement for grep, it's a replacement for find
That works by searching the contents of files. So, it is just a grep -l -R . 'search terms', right?

Edit: Actually, now that I am revisiting this thread. The top post hit my misunderstanding on the head.

It is a remarkable shame the author did not read the ack manpage to discover the '-g' option.
why not just find|grep <pattern>
find | grep foo