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

  • 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. – Rui F Ribeiro Jan 22 '18 at 12:25
  • @Rui: find is too much slower than locate. – Tim Jan 22 '18 at 12:25
  • Obviously. On the other hand, it just happens where and when you want it. – Rui F Ribeiro Jan 22 '18 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 '18 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 '18 at 12:34
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/'

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.