I'm trying to figure out the best and fastest way of finding files whose content is specifically "something"

Here's the reason: I have a process that I'm pretty sure stores its PID somewhere in a file, but I don't know where (and I want to find out). I have tried looking for filenames that may be used for storing said pid (/var/run/myproc.pid, and so on), but without success so far. I would like to give it a try searching for files whose content is just that number. I'd like to get the PID from ps -aux or top, or some tool like that and then search for files whose content is only that number.

I've been googling around but all the answers seem to explain how to find files that contain "something"... among its contents. I want something slightly different... I want an exact match of that "something"

Thank you in advance.

  • I'd go look at the documentation for the program you are running first to make sure it does indeed do what you think it does before going on a possible wild goose chase for a magic number across /var, /run, /tmp, etc. – jw013 Jul 26 '12 at 15:33
  • @jw013 Yeah, I tried that, but someone has been tweaking the code and it's not where it's supposed to be (inside the /var/run/ directory... it's somewhere else). Thanks for the hint, though. – BorrajaX Jul 26 '12 at 15:37

Something like ...

ps ax|grep ntpd|cut -b1-5|xargs -I PID find /var/run/ -type f -exec grep '-l' '^PID$' {} ';'

Note that the grep pattern specifies that the search string must be the only thing on the line, i.e. it's

string (PID is replace by value sent to `xargs`)

PS: I tested this by doing ps ax > /var/run/psaxdump followed by the above. It only found ntpd.pid

| improve this answer | |
  • Mixing in a head -1 would help avoid wasting time reading in any unexpectedly huge files. If you want to be truly pedantic, even that would have false positives for files that started with the PID on a line by itself but contained other data. – Jander Jul 27 '12 at 13:53
  • grep only does line-wise comparison. As Jander has noted above, this may result in false positives since any file containing the search string will match. Gilles' approach is much more sound. – jw013 Jul 27 '12 at 14:45

Put the desired text in a file, then run cmp on every candidate file.

pgrep myproc >/tmp/the_pid
find /var -type f -size $(wc -c </tmp/the_pid)c -exec cmp -s /tmp/the_pid {} \; -print

But for this use case, I would restart the program under strace -eopen or with an auditd rule:

auditctl -F "ppid=$$,a2&0x100" -S open
| improve this answer | |
  • 1
    that will spawn a lot of cmp processes that will exit once they see the file has a different size. using my answer find would do that statting and a lot less processes would be spawned – Janus Troelsen Jul 27 '12 at 17:41
  • @ysangkok Good point, which I'd noticed in your answer but didn't think of when writing mine (to recommend restarting and using strace, and also suggest cmp rather than diff). – Gilles 'SO- stop being evil' Jul 27 '12 at 18:03

You can pass a Regular Expression to grep, try this: (assuming PID is 67543)

grep -R '^67543$' /

In regular expression the ^ carrot (sp) symbol means "start of string", and the $ dollar sign symbol means "end of string", so the regex above will only return result where the file starts and ends with the string "67543".

| improve this answer | |
  • 1
    "only [...] where the file starts and ends". False! It will find all files with any matching line! $ grep -R "^donkey$" searchtree searchtree/test1:donkey $ od -c searchtree/test1 0000000 d o n k e y \n b i g m a n \n 0000017 – Janus Troelsen Jul 26 '12 at 15:18
  • @ysangkok That's why I didn't use extended regex. You are also uselessly "catting" a file, my example did not do such things. Don't just take bits and pieces of the code and paste it into incompatible code and expect it to work. – Tim Jul 26 '12 at 15:25
  • grep matches and returns lines, not files. A recursive grep will return any file containing a line that is an exact match. I don't think that was what the question asked. – jw013 Jul 26 '12 at 15:31
  • @Tim: The extended regex made no difference, I removed it. The catting was done to show you that the file had two lines even though we're searching for a file with one line. That's why I changed it to od. I'd change it more and make it prettier if the 5 min edit deadline hadn't expired. The od is not part of the solution, it is to show you that the grep gives the wrong result for this problem. – Janus Troelsen Jul 26 '12 at 15:40
find searchtree -type f -size `stat -c%s needle`c | xargs -n1 diff -s needle
| improve this answer | |
  • There must be something I'm doing wrong... Let's say I try to find 1234 in the files in /tmp/... If I do this: find /tmp/ -type f -size stat -c%s 1234c | xargs -n1 diff -s 1234 I get the following errors: stat: cannot stat 1234': No such file or directory find: Invalid argument c' to -size diff: missing operand after 1234' diff: Try diff --help' for more information. – BorrajaX Jul 26 '12 at 15:20
  • you get the command as output when you execute it? impossible – Janus Troelsen Jul 26 '12 at 15:21
  • try editing your question and append the errors, i think the comment box is too small – Janus Troelsen Jul 26 '12 at 15:22
  • Sorry, very bad case of copy/paste. I fixed it – BorrajaX Jul 26 '12 at 15:26
  • ah. you just need to put the pattern/needle in a file. you can do that with echo -n "thisiswhatiwanttosearchfor" > needle. remove "-n" if you want the trailing newline that you get per default in most textfiles. if your "needle" file is called "1234" of course you should use that instead of "needle". – Janus Troelsen Jul 26 '12 at 15:29

if pcregrep is available in your installation, you could pass the -l (list filename), -r (recursive) and -M (multiline) flags to it to get the job done. Note that \A and \Z represent start and end of string anchors. In the example below, 12477 is the string being searched

pcregrep -l -r -M '\A12477\Z' dir
| improve this answer | |

If your program isn't started at boot or together with a zillion of other programs, your pidfile should be as old as the process, which is less than one minute in the beginning.

If you know the PID, you know it's length, so you can reduce the number of files to search for even further:

 find -type f -mmin -1 -size 6c -exec grep 12345 {} \;

For a 5 digit PID use 6c as size, since they contain a trailing newline (from ysangkok as comment).

| improve this answer | |
  • 1
    the PID files have trailing newlines, so you need to change the 5 – Janus Troelsen Jul 26 '12 at 15:59

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.