2

How can I delete all directories/subdirectories from a tree which match the following conditions:

  1. Directory don't contain another subdirectory
  2. Directory contain just one file matching this regex pattern: ^\d{10}.jpg$ (ten digits with .jpg extension)

Executing the following command will return the desired folders but will also return directories with subdirectories

find . -type d -exec sh -c 'set -- "$0"/*.jpg; [ $# -le 1 ]' {} \; -print
Oliver Salzburg
  • 89,072
  • 65
  • 269
  • 311
SYNCRo
  • 123

2 Answers2

2

People have a fascination with one-liners (even though one can write scripts of arbitrary lengths which often makes things clearer), so let me first compress it into a single line of Bash :-) :

shopt -s globstar; for d in **/; do f=("$d"/*); [[ ${#f[@]} -eq 1 && -f "$f" && "${f##*/}" =~ ^[0-9]{10}\.jpg$ ]] && echo rm -r -- "$d"; done

where echo is a safeguard during testing.

The same code in an overly commented, more readable script version:

#!/bin/bash

# Enable double asterisk globbing (see `man bash`).
shopt -s globstar

# Loop through every subdirectory.
for d in **/; do
    # Glob a list of the files in the directory.
    f=("$d"/*)
    # If
    # 1. there is exactly 1 entry in the directory
    # 2. it is a file
    # 3. the file name consists of 10 digits with a ".jpg" suffix:
    if [[ ${#f[@]} -eq 1 && -f "$f" && "${f##*/}" =~ ^[0-9]{10}\.jpg$ ]]; then
        # `echo` to ensure a test run; remove when verified.
        echo rm -r -- "$d"
    fi
done

The matching is pure Bash (version ≥4), and I believe is not vulnerable to "tricky" file names, due to the globbing. By default it works from the current directory, but it could be modified to work on a given argument, a hardcoded path, etc.


ADDITION: To run in backwards globbing order of subdirectories to avoid having to do multiple iterations if this is a problem, one can first store the subdirectories in a variable and then traverse it backwards like this:

#!/bin/bash

# Enable double asterisk globbing (see `man bash`).
shopt -s globstar

# Glob every subdirectory.
subdirs=(**/)

# Loop directories in backwards lexical order to avoid multiple iterations.
for ((i=${#subdirs[@]}; i>0; --i)); do
    d=${subdirs[i-1]}
    # Glob a list of the files in the directory.
    f=("$d"/*)
    # If
    # 1. there is exactly 1 entry in the directory
    # 2. it is a file
    # 3. the file name consists of 10 digits with a ".jpg" suffix:
    if [[ ${#f[@]} -eq 1 && -f "$f" && "${f##*/}" =~ ^[0-9]{10}\.jpg$ ]]; then
        # `echo` to ensure a test run; remove when verified.
        echo rm -r -- "$d"
    fi
done

I think this will solve the issue in the comment, where some directories become eligible for removal only after the subdirectories have been handled (I will not update the one-liner, but everyone is free to do so for themselves :-) ).

0

Save your command's output and this command's output:

ls -lR | awk -F: '!($0 ~ ORS "d") && $0 ORS ~ "-" {print $1}' RS=

(This one finds directories without subdirectories)

And use "comm" command to check similar lines maybe?

seqizz
  • 91