2

I have a folder structure like this

|_folder1
| |_folder1.1
| | |_folder1.1.1
| |   |_img00
| |   |_...
| |_folder1.2
|   |_img00
|   |_...
|_folder2
  |_img00
  |_...

I want the script that combines images into pdfs to run at the leaf directories

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
giwedolus
  • 75
  • 3

2 Answers2

4

Now that you have the list of subdirectories, to get the leaf directories only, check for each directory to see if it has no subdirectory: check if *(/DN) is empty. You can add the glob qualifier Y1 to stop listing matches after the first.

for d in **/*(/DN); do
  sub=($d/*(/DNY1))
  if (($#sub)); then continue; fi
  process_leaf_directory $d
done

With most filesystems, there's an easier way: a leaf directory has a link count of 2 (only the entry for it in its parent directory and its . entry, whereas a non-leaf directory also has the .. entries in its subdirectories). This makes the filtering simpler: check for a link count of 2 with the glob qualifier l.

for d in **/*(/DNl2); do
  process_leaf_directory $d
done
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
3

The following find command would find every leaf directory under the current directory, and execute a script within it:

find . -type d -links 2 -execdir /path/to/script.sh some arguments here \;

This would execute the command given to -execdir in each leaf directory under the current directory.

The same, but using zsh (does not consider hidden names):

for dirpath in ./**/*(/l2); do
    ( cd "$dirpath" && /path/to/script.sh some arguments here )
done

The pattern ./**/*(/l2) would expand to the pathname of any leaf directories under the current directory. The ** matches recursively down into directory structures while *(/l2) would match any name that is a directory with a link count of exactly 2 (i.e. it's a directory with no subdirectories, a fact also used by the find command above).

Note that on some filesystems, like Apple's APFS, directories may have a link count greater than 2 even when they have no subdirectories. On BTRFS, the link count for directories is always 1. This solution would therefore not work on those filesystems.

Related:

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • `-execdir` runs the script in the **parent** of the selected directory, not the directory itself. – Stéphane Chazelas Oct 04 '19 at 10:11
  • That `-links 2` trick only works in some traditional Unix file systems and if no directory hard links other than `.` and `..` are ever created. It won't work on `btrfs` for instance where the link count for directories is always 1. – Stéphane Chazelas Oct 04 '19 at 10:12