what I want to do is to find all files based on some search query and get parents parent directory (../..) full path.

For example find . -name "__openerp__.py" and then for each file execute something along the lines of (cd ../..; pwd). Then pipe everything to uniq.


Assuming none of the file names contain newline characters:

find "$PWD" -name __openerp__.py  | awk -F/ -vOFS=/ 'NF-=2' | sort -u

Putting aside that there would be issues with file names that contain newlines, there are a couple of efficiency improvements I can think of:

  1. Pass the $PWD directly to find, instead of determining it for each sub-shell. This will make find include the full path in its output.
  2. Cut parent directory names off with rev and cut.

So I would suggest the following to get a list of all directories containing the desired file:

find "$PWD" -name '__openerp__.py' |
rev                                | 
cut -d/ -f3-                       |

Note that find does not order its output, so it should be sorted before uniq'ing it. As sort already supports squeezing identical elements (-u switch), the original question can then be answered with:

find "$PWD" -name '__openerp__.py' |
rev                                | 
cut -d/ -f3-                       |
rev                                |
sort -u
  • +1 Good point about sort -u. I initially thought that all the duplicate entries would be adjacent, but there isn't any reason for it. – Stéphane Chazelas Jan 29 '14 at 13:13

If I understand correctly, you want the list of directories containing a subdirectory containing a file called __openerp__.py, without duplicates.

In zsh:

print -rl -- **/__openerp__.py(:h:h) | sort -u


a=(**/__openerp__.py(:h:h)); print -rl -- ${(u)a}
  • +1 for (:h:h) didn't knew this one in zsh globbing. – JackLeo Jan 30 '14 at 11:18
find . -name "__openerp__.py" -exec sh -c '(cd "{}"/../../; pwd)' \; | uniq
  • 1
    Never include {} in the sh code. – Stéphane Chazelas Jan 29 '14 at 13:06
  • @StephaneChazelas why? – JackLeo Jan 29 '14 at 13:12
  • 3
    Because it's interpreted as shell code, so if you have for instance a file called $(rm -f "$HOME"), it will have expensive consequences. Also it doesn't work at all in many find implementations. Use sh -c 'cd -P "$1/../.." && pwd' sh {} \; instead. – Stéphane Chazelas Jan 29 '14 at 13:15

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.