1

How do I find files that contain a specific string and execute a command on these files?

In my case, I'd like to find all *.md files that contain the string

^  - HIMS$

and stage them with git.

I know I can find files containing the string via this command: grep -rlnw . -e ' - HIMS'

I also know that I can execute commands on found files via find:

find ./ -type f -name "*.md" -exec git add "{}" \;

Lastly, I know that I can use to find md files and grep:

find . -name '*.md' -exec grep -l '  - HIMS' {} \; -print

What I don't know is how I could add git add to either of the approaches.

I guess, the third approach, while being the slowest, might be the point to hook in. But I don't know how I append git add to it.

How do I achieve this?

1 Answers1

1

Your second find command:

find . -name '*.md' -exec grep -l '  - HIMS' {} \; -print

is redundant in its output. grep -l prints the pathnames of files you want, but then -exec is also a test in find. It succeeds iff the executed utility returns exit status zero. Exit status from grep deliberately reflects whether there was a match or not, so the tool can be used in a test like this. If the test succeeds, -print is evaluated. It prints the pathname grep has just printed.

Examine the output closely and you will see pathnames (lines) in pairs. In each pair the first line is from grep -l and the second is from find -print.

Now we know -exec is a test, we can insert it in your first find command. Your first find command was:

find ./ -type f -name "*.md" -exec git add "{}" \;

Here -type f is a test, -name "*.md" is another test; you can add yet another test before -exec git …:

find . -type f -name "*.md" -exec grep -q '  - HIMS' {} \; -exec git add {} \;

I used -q (quiet) instead of -l because we don't want the pathname from grep. For each file that passes preceding tests we want exit status from grep. The same mechanism that triggered -print in your second find command will now trigger the second -exec.

The second -exec is a test too, but there are no further tests or actions in our find, so this aspect is irrelevant in our case. In general -exec allows you to build custom tests. If you can write shell code or a script, or a program that tests what you want, then you can use it in find -exec. It's a very powerful tool.