1

I often use the following pipeline of locate (from findutils) and grep to find files whose pathnames contain two words word1 and word2, without any specific order between each other:

locate -i word1 | grep -i  word2

I was wondering how to do that with a single non-pipeline command alone? Is it a better way than my pipeline command?

Does locate support some regex in which we can formulate my search pattern?

Thanks.

Solution with find is https://unix.stackexchange.com/a/448006/674

15
  • 1
    locate assumes a background process scanning your disk via cron somewhere during the day. I prefer disabling it on servers and living with find. When you have hundred of servers you want to remove that kind of simultaneous "random" activity. Jan 22, 2018 at 12:25
  • @Rui: find is too much slower than locate.
    – Tim
    Jan 22, 2018 at 12:25
  • Obviously. On the other hand, it just happens where and when you want it. Jan 22, 2018 at 12:26
  • Are you sure that the updating of the database of locate is scheduled by cron, where can I find it out?
    – Tim
    Jan 22, 2018 at 12:27
  • 3
    some versions of locate support regex searches....but, like grep, they don't support AND or AND NOT logical operations (probably because alternation aka OR is easy, but AND would require either a new regex style or a wrapper language around regexes). so, piping into another tool like grep or grep -v is the standard solution.
    – cas
    Jan 22, 2018 at 12:34

1 Answer 1

2

That very much depends on your implementation of locate. That's not a standard command and there are a few different implementations with quite significant differences.

  1. There's one implementation in GNU findutils.

    With that one:

    locate -i word1 word2
    

    locates files whose path contains either word1 or word2 case insensitively while

    locate -Ai word1 word2
    

    locates files whose path contains both.

    It also supports a --regex and --regextype option like for GNU find. By defaut, that's emacs-style regexps, some form of hybrid between BRE and ERE.

    With that one, you could do:

    locate -ir 'word1.*word2\|word2.*word1'
    
  2. The mlocate implementation (the default on Debian and derivatives) also support -A. It has -r/--regex, but not --regextype and its REs are Basic Regular Expressions. On systems like GNU ones whose BREs support \| for alternation as an extension, you can also do:

    locate -ir 'word1.*word2\|word2.*word1'
    
  3. ast-open has a locate as well as a ksh93 wrapper script around tw (the once to be successor of find). It doesn't support -A nor -r, but you can use the full power of ksh93 wildcards, so you can use for instance perl-like look-ahead operators with:

    locate '~(Pi:^(?=.*word1)(?=.*word2))'
    

    Or ksh93's & glob operator:

    locate -i '*word1*&*word2*'
    

    It's particularly slow compared to the other ones though as the pattern is not anchored. It's better once anchoring (left and right) is restored with:

    locate -i '~(lr)*word1*&*word2*'
    

One problem with piping to grep is that it doesn't work for file path that contain newline characters. With GNU locate or mlocate, you can use the -0 option though to use NUL-delimited records which you can use in combination with the -z option of GNU grep:

locate -i0 word1 | grep -z word2 | grep -z word3 | tr '\0' '\n'

Or -v RS='\0' in GNU gawk or @ThomasDickey's mawk:

locate -i0 word1 | awk -v RS='\0' '/word2/ && /word3/'

Or perl -ln0:

locate -i0 word1 | perl -ln0e 'print if /word2/ && /word3/'

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .