Extract the directory path containing the file with matching string
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 e
valuates true it prints only the h
ead 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
.
Related videos on Youtube
rambalachandran
An engineer trying to get insights from data
Updated on September 18, 2022Comments
-
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
inresults.out
and extract the directory path of thoseresults.out
that contain thestring1
, since I need to move these sub-directories to another location. For example, I can get the file path using the following codefor 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 almost 8 yearsEven 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 almost 8 yearsNot all
dirname
implementations accept more than one argument. (POSIXdirname
specification doesn't). As usual withxargs
, 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 onegrep
per file.