How to find directories where certain files exist but some others don't

Unix & Linux Asked by John Zhau on October 6, 2020

Let’s say I have lots of directories for reports and I always have a file in directories with reports but report.pdf only in finished reports. I want to find directories where exists but without report.pdf.

+-- project_xyz
|   +--
|   +-- image.png
+-- bugs
|   +--
|   +-- report.pdf
|   +-- Makefile
+-- homework
    +-- report.pdf

If I use this function as search "reports_dir" --include "" --exclude "report.pdf", it should return /project_xyz but not /bugs and /homework

What’s the quickest way to do such a search in sh/bash? (one-liner preferred)

5 Answers

Maybe this will work?

comm -23 <(find -name "" -printf '%hn' | sort) <(find -name "report.pdf" -printf '%hn' | sort)

Answered by nezabudka on October 6, 2020

With zsh:

print -rC1 -- **/^e['[[ -e $REPLY:r.pdf ]]']:h)

Would print raw on 1 Column the head (dirname) of the files under any level of subdirectories (**/) including Dot (hidden) ones, for which the evaluation of the [[ -e $REPLY:r.pdf ]] code does not (^) return true (where $REPLY:r is the root name of $REPLY containing the file to check).

With find implementations (such as GNU find) that allow {} embedded in -exec arguments and any Bourne-like shell (including bash), you can do:

find . -type d -exec test -e '{}/' ; 
             ! -exec test -e '{}/report.pdf' ; -print

Though that means executing up to 2 test commands per directory.

With bosh and its find builtin, that can be avoided with:

find . -type d -call '
  [ -e "$1/" ] && [ ! -e "$1/report.pdf" ]' {} ; -print

Where this time, -call has the shell interpret that code directly and invokes the builtin [.


find . -type d -exec sh -c '
  for d do
    [ ! -e "$d/" ] || [ -e "$d/report.pdf" ] || printf "%sn" "$d"
  done' sh {} +

With those sh implementations where [ and printf are builtin (most, these days), that should be relatively efficient as as few sh as possible are invoked by find to process the list of directories it finds.

Answered by Stéphane Chazelas on October 6, 2020

You can use a short bash one-liner to test fore the existence of the PDF ( -exec is also a filter):

find . -name '*.md' -exec bash -c '[[ -f "${1%.*}.pdf" ]] && exit 1; exit 0;' bash-line {} ; -print

If you only want the directory name you can also put it in another -exec after the first one (find stops after the first test):

find . -name '*.md' -exec bash -c '[[ -f "${1%.*}.pdf" ]] && exit 1; exit 0;' bash-line {} ; -exec dirname {} ;

Answered by xenoid on October 6, 2020

You could try this, although the output could be a bit messy, ls -R | grep | grep -v report.pdf The ls -R here lists directories reccursively, then greps and grep -v means anything with report.pdf will be ignored.

Answered by honeymoly on October 6, 2020

for f in "$1"/*/"$2"; do dir=$(dirname -- "$f"); [ -f "$dir/$3" ] || printf '%sn' "$dir"; done

Save the script as search. The first argument is the parent directory, the second is the include and the third the exclude.

sh search "reports_dir" "" "report.pdf"
  • "$1"/*/"$2" gets only the path of the files in the example.

  • dir=$(dirname -- "$f") gets the directory path of those files (assumes it doesn't end in newline characters).

  • [ -f "$dir/$3" ] tests for the existence of the file in 3rd argument in that directory (report.pdf) and that's it's of regular type (not a directory, fifo, device...).

  • || printf '%sn' "$dir" if it does not exist (or is not a regular file), print the directory name.

Answered by Quasímodo on October 6, 2020

Add your own answers!

Related Questions

Where are firewalld rules stored on disk?

1  Asked on December 1, 2021


append file & directory to /

1  Asked on December 1, 2021 by zoom80


Setting up Samba as AD DC

1  Asked on November 28, 2021 by davework


Cant make use of grub-mkimage

1  Asked on November 28, 2021


What are systemd runtime unit files for?

3  Asked on November 28, 2021 by adam-pickering


SSH Secure Copy Denied/Timed Out

2  Asked on November 28, 2021 by z-bird


Ask a Question

Get help from others!

© 2022 All rights reserved. Sites we Love: PCI Database, MenuIva, UKBizDB, Menu Kuliner, Sharing RPP