Утилита для поиска дубликатов папок (НЕ файлов)

Я знаю о rdfind которые могут найти дубликаты файлов в двух каталогах. Но мне нужна похожая утилита, которая находит дубликаты папок (папки с одинаковым именем и одинаковым путем относительно основных каталогов) в двух основных каталогах. Есть ли утилита, которая делает эту простую задачу?

**Example:**
$ tree
.
├── maindir1
│   ├── dir space
│   │   ├── dir1
│   │   └── dir2
│   ├── dir1
│   ├── dir2
│   │   └── new\012line
│   ├── dir3
│   │   └── dir5
│   └── dir4
│       └── dir6
├── maindir2
│   ├── dir space
│   │   └── dir2
│   ├── dir1
│   ├── dir2
│   │   └── new\012line
│   ├── dir5
│   │   └── dir6
│   ├── dir6
│   └── new\012line
├── file
└── new\012line

ПРИМЕЧАНИЕ. В приведенном выше примере единственными дублирующимися папками на первом уровне (глубина 1) являются:

maindir1/dir space/ & maindir2/dir space/
maindir1/dir1/ & maindir2/dir1/
maindir1/dir2/ & maindir2/dir2/

На втором уровне (глубина 2) единственными дублирующимися папками являются:

maindir1/dir space/dir2/ & maindir2/dir space/dir2/
maindir1/dir2/new\012line/ & maindir2/dir2/new\012line/

Обратите внимание, что maindir1/dir3/dir5/ а также maindir2/dir5/ не являются дубликатами, а также maindir1/dir4/dir6/ а также maindir2/dir5/dir6/ не являются дубликатами.

1 ответ

Я не знаю ни одной утилиты, специфичной для каталогов (но такие вещи, как fslint или же fdupes должен также перечислить каталоги), но это достаточно легко для сценария:

#!/usr/bin/env bash

## Declare $dirs and $count as associative arrays
declare -A dirs
declare -A count

find_dirs(){
    ## Make ** recurse into subdirectories
    shopt -s globstar
    for d in "$1"/**
    do
    ## Remove the top directory from the dir's path
    dd="${d#*/}"
    ## If this is a directory, and is not the top directory
    if [[ -d "$d" && "$dd" != "" ]]
    then
        ## Count the number of times it's been seen
        let count["$dd"]++
        ## Add it to the list of paths with that name.
        ## I am using the `&` to separate directory entries
        dirs["$dd"]="${dirs[$dd]} & $d" 
    fi

    done
}

## Iterate over the list of paths given as arguments
for target in "$@"
do
    ## Run the find_dirs function on each of them
    find_dirs "$target"
done

## For each directory found by find_dirs
for d in "${!dirs[@]}"
do
    ## If this name has been seen more than once
    if [[ ${count["$d"]} > 1 ]]
    then
    ## Print the name with pretty colors
    printf '\033[01;31m+++ NAME: "%s" +++\033[00m\n' "$d"
    ## Print the paths with that name
    printf "%s\n" "${dirs[$d]}" | sed 's/^ & //'
    fi
done

Приведенный выше сценарий может работать с произвольными именами каталогов (в том числе с пробелами или даже символами новой строки в их именах) и повторяться в любом количестве подкаталогов. Например, в этой структуре каталогов:

$ tree
.
├── maindir1
│   ├── dir1
│   ├── dir2
│   │   └── new\012line
│   ├── dir3
│   │   └── dir5
│   ├── dir4
│   │   └── dir6
│   └── dir space
│       ├── dir1
│       └── dir2
└── maindir2
    ├── dir1
    ├── dir2
    │   └── new\012line
    ├── dir5
    │   └── dir6
    ├── dir6
    ├── dir space
    │   └── dir2
    └── new\012line

Это вернет это:

Другие вопросы по тегам