Как я могу сравнить два каталога рекурсивно и проверить, содержит ли один из каталогов другой?

У меня есть два каталога, они содержат общие файлы. Я хочу знать, содержит ли один каталог тот же файл как другой. Я нашел сценарий в сети, но я хочу должен улучшить ее, чтобы сделать рекурсивно.

  #!/bin/bash

  # cmp_dir - program to compare two directories

  # Check for required arguments
  if [ $# -ne 2 ]; then
      echo "usage: $0 directory_1 directory_2" 1>&2
      exit 1
  fi

  # Make sure both arguments are directories
  if [ ! -d $1 ]; then
      echo "$1 is not a directory!" 1>&2
      exit 1
  fi

  if [ ! -d $2 ]; then
      echo "$2 is not a directory!" 1>&2
      exit 1
  fi

  # Process each file in directory_1, comparing it to directory_2
  missing=0
  for filename in $1/*; do
      fn=$(basename "$filename")
      if [ -f "$filename" ]; then
          if [ ! -f "$2/$fn" ]; then
              echo "$fn is missing from $2"
              missing=$((missing + 1))
          fi
      fi
  done
  echo "$missing files missing"

Кто-либо предложил бы алгоритм для него?

2
задан 25 June 2014 в 18:34

3 ответа

#!/bin/bash

# cmp_dir - program to compare two directories

# Check for required arguments
if [ $# -ne 2 ]; then
  echo "usage: $0 directory_1 directory_2" 1>&2
  exit 1
fi

# Make sure both arguments are directories
if [ ! -d "$1" ]; then
  echo "$1 is not a directory!" 1>&2
  exit 1
fi

if [ ! -d "$2" ]; then
  echo "$2 is not a directory!" 1>&2
  exit 1
fi

# Process each file in directory_1, comparing it to directory_2
missing=0
while IFS= read -r -d $'\0' filename
do
  fn=${filename#$1}
  if [ ! -f "$2/$fn" ]; then
      echo "$fn is missing from $2"
      missing=$((missing + 1))
  fi
done < <(find "$1" -type f -print0)

echo "$missing files missing"

Обратите внимание, что я добавил двойные кавычки вокруг $1 и $2 в различных местах выше для защиты их окружают расширение. Без двойных кавычек имена каталогов с пробелами или другими трудными символами вызвали бы ошибки.

Ключевой цикл теперь читает:

while IFS= read -r -d $'\0' filename
do
  fn=${filename#$1}
  if [ ! -f "$2/$fn" ]; then
      echo "$fn is missing from $2"
      missing=$((missing + 1))
  fi
done < <(find "$1" -type f -print0)

Это использует find рекурсивно погружаться в каталог $1 и найдите имена файлов. Конструкция while IFS= read -r -d $'\0' filename; do .... done < <(find "$1" -type f -print0) безопасно против всех имен файлов.

basename больше не используется, потому что мы смотрим на файлы в подкаталогах, и мы должны сохранить подкаталоги. Так, вместо вызова к basename, строка fn=${filename#$1} используется. Это просто удаляет из filename префикс, содержащий каталог $1.

Проблема 2

Предположим, что мы соответствуем файлам по имени, но независимо от каталога. Другими словами, если первый каталог содержит файл a/b/c/some.txt, мы будем считать это существующим во втором каталоге если файл some.txt существует в любом подкаталоге второго каталога. Сделать эту замену цикл выше с:

while IFS= read -r -d $'\0' filename
do
  fn=$(basename "$filename")
  if ! find "$2" -name "$fn" | grep -q . ; then
      echo "$fn is missing from $2"
      missing=$((missing + 1))
  fi
done < <(find "$1" -type f -print0)
7
ответ дан 25 June 2014 в 18:34

FSlint является маленьким приложением GUI, которое помогает Вам определить и убрать свою систему избыточных файлов.

Установка FSlint

Установите FSlint от Центра программного обеспечения Ubuntu, или из командной строки следующим образом:

sudo apt-get install fslint

(В моей системе, устанавливая FSlint не вытягивал в дополнительных зависимостях. А именно, fslint зависит от findutils, Python и python-glade2, который уже должен все быть в Вашей системе. Можно удалить FSlint использование Центра программного обеспечения или путем ввода sudo apt-get autoremove --purge fslint в терминале).

Поиск файлов

Запустите FSlint от тире единицы.

Вот снимок экрана основного экрана. Существует много расширенных функций, но основное использование приложения относительно просто.

Нажмите Add кнопка наверху уехала для добавления всех каталогов, которые требуется проверить. Очевидно, можно удалить каталоги с помощью Remove кнопка.

enter image description here

Удостоверьтесь recurse? флажок в право устанавливается. Затем нажмите Find кнопка. (Любые ошибки, такие как разрешение файла проблемы, будут распечатаны у основания окна FSlint).

FSlint перечислит все дубликаты файлов, их местоположения каталога и дату файла. FSlint также дарит Вам число байтов, потраченных впустую из-за избыточных файлов.

Удаление дубликатов

Теперь можно выбрать несколько файлов с помощью клавиш Shift или клавиш Ctrl и левой кнопки мыши. Если Вы хотите выбрать несколько файлов автоматически, нажмите Select кнопке и Вам дадут опции, такие как выбор файлов на основе даты или ввода подстановочных критериев выбора.

Если необходимо использовать список выбранных файлов за пределами FSlint (возможно, как введено к собственному сценарию), нажимают Save кнопка для сохранения текстового файла.

Наконец можно удалить выбранные файлы с помощью Delete кнопка, или можно объединить выбранные файлы с помощью Merge кнопка. Обратите внимание что Merge функция удаляет отмененные выбор файлы из Вашей системы и создает жесткие ссылки на соответствующие выбранные файлы. Вы использовали бы эту функцию, если бы Вы хотели сохранить свою существующую файловую структуру, но хотели освободить некоторое пространство в своей системе.

enter image description here

Дополнительные функции и Документация

FSlint имеет другие мощные функции, которые доступны от вкладок в левой панели. Я нашел Name clashes чтобы быть полезным, где существуют файлы, которые имеют то же имя, но отличаются (возможно, потому что Вы сохранили более новую версию файла в другом каталоге).

Существует также Advanced search parameters вкладка наверху окна FSlint, которое позволяет Вам исключать определенные каталоги в своем поиске или фильтровать Ваши результаты с помощью параметров.

Там ре много мощных функций в этом простом небольшом инструменте. Это может сохранить Вас усилие по необходимости записать и отладить сценарий. Можно узнать больше по http://www.pixelbeat.org/fslint/. Вот прямая ссылка на английское руководство: http://en.flossmanuals.net/fslint/.

3
ответ дан 25 June 2014 в 18:34

Я хочу совместно использовать этот путь, потому что я думаю, что это довольно забавно.

Для каждой подпапки ниже целевой папки, мы генерируем хеш для той подпапки.

Каждый хеш папки сгенерирован от результата хеширования всех файлов ниже той папки. Таким образом, любая папка, содержащая идентичные файлы в той же структуре, должна произвести тот же хеш!

В конце, мы используем uniq для отображения только дублирующихся хешей папки.

Сохраняют следующий сценарий как seek_duplicate_folders.sh и затем выполняют его как это:

$ bash seek_duplicate_folders.sh [root_folder_to_scan]

Вот сценарий:

#!/bin/bash
target="$1"

hash_folder() {
  echo "Hashing $1" >/dev/stderr
  pushd "$1" >/dev/null

  # Hash all the files
  find . -type f | sort | xargs md5sum |

  # Hash that list of hashes, discard the newline character,
  # and append the folder name
  md5sum - | tr -d '\n'
  printf "  %s\n" "$1"

  popd >/dev/null
}

find "$target" -type d |
while read dir
do hash_folder "$dir"
done |
sort |
# Display only the lines with duplicate hashes (first 32 chars are duplicates)
uniq -D -w 32

Протесты:

  • Неэффективный: это md5sums файлы глубоко в дереве многократно (однажды на папку предка)
  • не обнаруживают различия в метках времени файла, владении или полномочиях
  • , Игнорирует пустые папки. Таким образом, о двух папках, которые содержат идентичные файлы или никакие файлы, но имеют различные пустые папки в них, все еще сообщат как идентичных.
  • Игнорирует символьные ссылки. О файлах, содержащих различные символьные ссылки, можно все еще сообщить как идентичных.
0
ответ дан 26 June 2014 в 05:34
  • 1
    Я отредактировал вопрос во второй раз с большим количеством информации. – gregoiregentil 8 December 2015 в 19:09

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

Похожие вопросы: