Extract the directory path containing the file with matching string

5,013

Solution 1

If you have GNU find, you can print the path using the %h format specifier

    %h     Leading directories of file's name (all but the last ele‐
           ment).  If the file name contains no slashes (since it is
           in  the  current  directory)  the %h specifier expands to
           ".".

So for example you could do

find . -name 'results.out' -exec grep -q 'string1' {} \; -printf '%h\n'

Solution 2

With zsh:

print -rl ./**/results.out(.e_'grep -q string $REPLY'_:h)

this searches recursively for regular files (.) named results.out, runs grep -q ... on each of them and if that evaluates true it prints only the head of the path (the path without the last element).


Another way with find and sh, using parameter expansion to extract the head:

find . -type f -name results.out -exec grep -q string {} \; \
-exec sh -c 'printf %s\\n "${0%/*}"' {} \;

Solution 3

for i in $(find . -type f -name "results.out);
do
grep -l "string1" $i ; exitcode=${?}
if [ ${exitcode} -eq 0 ]  # string1 is found in file $i
then
   path=${i%/*}
   echo ${path}
fi
done

Solution 4

On a GNU system:

 find . -depth -type f -name results.out -exec grep -lZ string1 {} + |
   xargs -r0 dirname -z |
   xargs -r0 mv -t /dest/dir

Or:

 find . -depth -type f -name results.out -exec grep -lZ string1 {} + |
   LC_ALL=C sed -z 's|/[^/]*$||' |
   xargs -r0 mv -t /dest/dir

The -depth is so that if both ./A/results.out and ./A/B/results.out match, ./A/B is moved to /dest/dir/B before ./A is moved to /dest/dir/A.

Share:
5,013

Related videos on Youtube

rambalachandran
Author by

rambalachandran

An engineer trying to get insights from data

Updated on September 18, 2022

Comments

  • rambalachandran
    rambalachandran over 1 year

    I have multiple subdirectories at multiple levels containing a file results.out

    ./dir1/results.out
    ./dir2/dir21/results.out
    ./dir3/dir31/dir311/results.out
    

    Now I need to search for string1 in results.out and extract the directory path of those results.out that contain the string1, since I need to move these sub-directories to another location. For example, I can get the file path using the following code

    for i in $(find . -type f -name "results.out);
    do
    grep -l "string1" $i
    done
    

    How to modify the above code to get only the directory path?

  • MelBurslan
    MelBurslan almost 8 years
    Even though dirname is available in any recent distribution of Linux, it is still an external command and might not be available on minimally installed systems. Just a word of caution.
  • Stéphane Chazelas
    Stéphane Chazelas almost 8 years
    Not all dirname implementations accept more than one argument. (POSIX dirname specification doesn't). As usual with xargs, you'll also have issues with file paths containing blanks or quotes or backslash. You may as well use \; instead of + here to avoid having to run one grep per file.