find . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort |uniq
Os itens acima encontram todos os arquivos abaixo do diretório atual ( . ) que são arquivos regulares ( -type f ) e têm f em algum lugar em seu nome ( -name '*f*' ). Em seguida, sed remove o nome do arquivo, deixando apenas o nome do diretório. Em seguida, a lista de diretórios é classificada ( sort ) e as duplicatas são removidas ( uniq ).
O comando sed consiste em um único substituto. Ele procura por correspondências com a expressão regular /[^/]+$ e substitui qualquer coisa que corresponda a isso com nada. O cifrão significa o fim da linha. [^/]+' significa um ou mais caracteres que não são barras. Portanto, /[^/]+$ significa todos os caracteres da barra final até o final da linha. Em outras palavras, isso corresponde ao nome do arquivo no final do caminho completo. Assim, o comando sed remove o nome do arquivo, deixando inalterado o nome do diretório em que o arquivo estava.
Simplificações
Muitos comandos sort modernos suportam um sinal -u , o que torna uniq desnecessária. Para o GNU sed:
find . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort -u
E, para o MacOS sed:
find . -type f -name '*f*' | sed -E 's|/[^/]+$||' |sort -u
Além disso, se o seu comando find for compatível, é possível ter find imprimir os nomes dos diretórios diretamente. Isso evita a necessidade de sed :
find . -type f -name '*f*' -printf '%h\n' | sort -u
Versão mais robusta (requer ferramentas GNU)
As versões acima serão confundidas por nomes de arquivos que incluem novas linhas. Uma solução mais robusta é fazer a classificação em strings terminadas em NUL:
find . -type f -name '*f*' -printf '%hfind . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort |uniq
' | sort -zu | sed -z 's/$/\n/'