1

How can I find the directories where a text is found in a specific file? E.g. I want to get all the directories in "/var/www/" that contain the text "foo-bundle" in the composer.json file. I have a command that already does it:

find ./ -maxdepth 2 -type f -print | grep -i 'composer.json' | xargs grep -i '"foo-bundle"'

However I want to make an sh script that gets all those directories and do things with them. Any idea?

Manolo
  • 24,020
  • 20
  • 85
  • 130

3 Answers3

2

Your current command is almost there, instead off using xargs with grep, lets:

  1. Move the grep to an -exec
  2. Use xargs to pass the result to dirname to show only the parent folder
find ./ -maxdepth 2 -type f -exec grep -l "foo-bundle" {} /dev/null \; | xargs dirname

If you only want to search for composer.json files, we can include the -iname option like so:

find ./ -maxdepth 2 -type f -iname '*composer.json' -exec grep -l "foo-bundle" {} /dev/null \; | xargs dirname

If the | xargs dirname doesn't give enough data, we can extend it so we can loop over the results of find using a while read like so:

find ./ -maxdepth 2 -type f -iname '*composer.json' -exec grep -l "foo-bundle" {} /dev/null \; | while read -r line ; do
    parent="$(dirname ${line%%:*})"
    echo "$parent"
done

We can use to search for all files containing a specific text.

After looping over each line, we can

  1. Remove behind the : to get the filepath
  2. Use dirname to get the parent folder path

Consider this file setup, were /test/b/composer.json contains foo-bundle

➜  /tmp tree
.
├── test
│   ├── a
│   │   └── composer.json
│   └── b
│       └── composer.json
└── test.sh

When running the following test.sh:

#!/bin/bash

grep -rw '/tmp/test' --include '*composer.json' -e 'foo-bundle' | while read -r line ; do
    parent="$(dirname ${line%:*})"
    echo "$parent"
done

The result is as expected, the path to folder b:

/tmp/test/b
0stone0
  • 34,288
  • 4
  • 39
  • 64
  • This is a recursive grep, my directories are too large for that. I only need the grep over the composer.json file – Manolo Oct 29 '21 at 10:44
  • Oeps, forgot to add that. We can use `--include '*composer.json'` to let grep only search the composer files. I've edited my answer! – 0stone0 Oct 29 '21 at 10:47
  • It's still a recursive grep. It takes too long. I should read only the second level directory – Manolo Oct 29 '21 at 11:04
  • However, I think I can get it combining my find command with your while logic. I'll give a try – Manolo Oct 29 '21 at 11:08
  • Ahh, not sure if `grep` has an `max-depth` like option. I'd recommend using the first `find` way. – 0stone0 Oct 29 '21 at 11:09
1

In order to find all files, containing a particular piece of text, you can use:

find ./ -maxdepth 2 -type f -exec grep -l "composer.json" {} /dev/null \;

The result is a list of filenames. Now all you need to do is to get a way to launch the command dirname on all of them. (I tried using a simple pipe, but that would have been too easy :-) )

Dominique
  • 16,450
  • 15
  • 56
  • 112
0

Thanks to @0stone0 for leading the way. I finally got it with:

#!/bin/sh

find /var/www -maxdepth 2 -type f -print | grep -i 'composer.json' | xargs grep -i 'foo-bundle' | while read -r line ; do
    parent="$(dirname ${line%%:*})"
    echo "$parent"
done
Manolo
  • 24,020
  • 20
  • 85
  • 130
  • Please see my [edited answer](https://stackoverflow.com/a/69766911/5625547). We can remove 1 pipe by using the `-iname` option of `find`. Might increase the speed since we don't need to use a pipe. – 0stone0 Oct 29 '21 at 13:48