Why does pipe not work with cat and locate?

20,041

Solution 1

locate -e0 '*/pg_type.h' | xargs -r0 cat

locate pg_type.h would find all the files with pg_type.h in their path (so for instance if there was a rpg_type.horn directory, you'd end up displaying all the files in there).

Without -0 the output of locate can't be post-processed because the files are separated by newline characters while newline is a perfectly valid character in a file name.

cat without arguments writes to stdout what it reads from stdin, so locate | cat would be the same as locate, cat would just pass the output of locate along. What you need is to pass the list of files as arguments to cat.

That's what xargs is typically for: convert a stream of data into a list of arguments. -r is to not call cat if there's no input. Without -0 (which like -r is not standard but found on many implementations, at least those where xargs is useful to anything), xargs would just look for words in its input to convert into arguments, where words are blank separated and where backslash, single and double quotes can be used to escape those separators, so typically not the format locate uses to display file names.

That's why we use the -0 option for both locate and xargs which uses the NUL character (which is the only character not allowed in a file path) to separate file names.

Also note that locate is not a standard command and there exist a great number of different implementations with different versions thereof and different options and behaviours. The code above applies at least to relatively recent versions of the GNU locate and mlocate implementations which are the most common on Linux based operating systems at least.

Solution 2

Your command passes the output of locate to cat on standard-in. That's not what you want. What you want is to pass the output of locate to cat as an argument.

I believe the way to do that is with xargs:

locate pg_type.h | xargs cat
Share:
20,041

Related videos on Youtube

Stephane Rolland
Author by

Stephane Rolland

Updated on September 18, 2022

Comments

  • Stephane Rolland
    Stephane Rolland over 1 year

    I am trying to perform this:

    locate pg_type.h | cat
    

    But this command simply does nothing different than locate pg_type.h

    What should I change ? I want to perform cat pg_type.h wherever pg_type.h may be.

    • Wildcard
      Wildcard over 7 years
      Also note that locate is not reliable for information about what is on your filesystem right now.
  • goldilocks
    goldilocks about 11 years
    You can also do this with backticks or $(), eg cat $(locate pg_type.h).
  • Stéphane Chazelas
    Stéphane Chazelas about 11 years
    That assumes none of the paths returned by locate contain any space, tab, newline, blackslash, single or double quote characters. And for $() (@goldilocks), no spc, tab, newline or globbing (*, ?, [) characters.
  • goldilocks
    goldilocks about 11 years
    @StephaneChazelas : Yep. But who would put silly things like that in a path? ;) ;)
  • Stéphane Chazelas
    Stéphane Chazelas about 11 years
    @goldilocks, Windows/Mac users or anybody that may want to exploit the bug that you're introducing. For instance, if you run that line as root and the output ends up in somewhere world-readable, then somebody may want to create a file called /tmp/ /etc/shadow /pg_type.h to be able to have a look at the content of the /etc/shadow file. Remember some bugs end up being security vulnerabilities, some of which end up exploited. Lets try and have as few bugs as possible in the first place. And that starts with teaching good practice here (or at least mention the limitations/risks).
  • SlySven
    SlySven almost 8 years
    A bit late to the discussion but remember that locate uses a previously constructed index/cache as its source of data (usually rebuild regularly with a cron job) which can be updated manually (typically with a sudo updatedb - it often needs elevated privileges to read some areas of the file-system!) c.f. find walks and reports on the file-system at run time so it will return current details at the time it finds them. In comparison locate is faster at the time you use it (especially if you have to refine/repeat your search) whereas find is more current in data it returns...