Разделение большого дерева каталогов по типу файла

У меня есть большой каталог данных (20-30Gb) на моем настольном компьютере Ubuntu 10.10, который состоит из множества файлов необработанных данных, обработанных файлов данных и различных скриптов, таблиц, цифр и т. Д., Сгенерированных из обработанных данных. Каталог данных накопился на протяжении многих лет и очень плохо структурирован – «в один прекрасный день» я разобрался, но всегда есть более важные вещи.

Теперь я перехожу к онлайн-службе резервного копирования, и чтобы сократить время, затрачиваемое на резервное копирование и необходимое онлайн-хранилище, я хотел бы разделить необработанные данные, которые занимают много места, но их легко заменить уже архивируется в другом месте, сохраняя свою общую позицию в структуре каталогов. Другими словами, я хочу перейти от чего-то вроде:

/data/A/raw1.data /data/A/raw2.data /data/A/raw3.data /data/A/processed.txt /data/A/figure.eps /data/A/plot.gnu /data/B/raw4.data /data/B/processed.txt ... etc. 

в

 /data/A/processed.txt /data/A/figure.eps /data/A/plot.gnu /data/B/processed.txt ... etc. 

а также

 /raw_data/A/raw1.data /raw_data/A/raw2.data /raw_data/A/raw3.data /raw_data/B/raw4.data ... etc. 

Таким образом, необработанные файлы данных меняются из / data в / raw_data, но в остальном сохраняют свою позицию в структуре каталогов, тогда как обработанные данные и связанные с ними файлы остаются в одном месте. Общая структура файлов намного сложнее и беспорядочна, но экономия заключается в том, что все необработанные данные могут быть идентифицированы по типу filetype (в основном .fits и .sdf).

Я уверен, что это тривиально с правильной комбинацией команд и / или несколькими строками сценария bash, но мои знания в командной строке ограничены основами, и я бы предпочел спросить, чем риск взломать ее 🙂

И, в стороне, есть простой способ поиска дубликатов в необработанных данных – будет иметь идентичное имя файла + размер, не обязательно временную метку, которая будет сброшена, поскольку данные будут загружены из архива, хотя, чтобы быть абсолютно уверенным, мне нужно проведите каждый дубликат кандидата через dfits и grep отметьте метку времени в заголовке fits.

2 Solutions collect form web for “Разделение большого дерева каталогов по типу файла”

Одним из способов сделать это было бы использование rsync с некоторыми специально разработанными правилами include / exclude и возможностью удаления исходных файлов после синхронизации следующим образом:

 rsync -av --include "*/" --include='*.fits' --include='*.sdf' \ --exclude='*' --remove-source-files /data/ /raw_data/ 

Если вы хотите переместить шаг за шагом в цикл, чтобы вы могли потенциально включить другие действия, вам понадобится скрипт, который сделает что-то вроде этого:

 DIR1="/data" DIR2="/raw_data" find "$DIR1" -type f \( -iname '*.fits' -or -iname '*.sdf' \) -print0 | while read -d $'\0' file; do mkdir -p "$DIR2/$(basename "$file")" mv "$file" "$DIR2/$(basename "$file")" done 

Существует множество инструментов копирования файлов, которые позволяют создавать целевое имя каталога с достаточно гибкими правилами ( zcp , rsync , pax , …). К сожалению, некоторые из них позволяют перемещаться (в противоположность копированию) и создавать целевые каталоги по требованию. Поэтому я покажу несколько способов сделать это за два прохода: сначала создайте все потенциально необходимые целевые каталоги, а затем выполните переход.

Перл переименовать

Программа rename Perl, поставляемая Debian и Ubuntu, может при необходимости создать целевой каталог, если вы напишете необходимый бит Perl.

 shopt -s globstar # make **/ traverse directories recursively (requires bash 4) rename 'BEGIN {use File::Path} s!^/data!/raw_data!; m!(.*)/!; mkpath($1)' /data/**/*.raw 

В zsh опустите линию shopt -s globstar ; ** означает рекурсивный обход по умолчанию. В оболочках, отличных от bash и zsh, вам нужно использовать find для рекурсивных обходов (см. Примеры ниже). Не беспокойтесь обо всем этом, если у вас есть один уровень каталогов.

Создание целевых каталогов

В zsh (пояснение: определитель / glob означает соответствие только каталогам, а определитель e glob применяет преобразование, указанное впоследствии к каждому имени):

 mkdir /data/**/*(/e\''REPLY=${REPLY/data/raw_data}'\') 

С другими оболочками:

 find /data -type d \ -exec sh -c 'for d; do mkdir "/raw_data${d#/data}"; done' _ {} + 

Если у вас только один уровень подкаталогов, это намного проще:

 for d in /data/*/; do mkdir "/raw_data${d#/data}"; done 

Перемещение файлов (zsh)

 autoload zmv zmv -Q '/data/(**/)(*.raw)(.)' '/raw_data/$1$2' 

Перемещение файлов (переносных)

 find /data -name '*.raw' \ -exec sh -c 'for x; do mv "$x" "/raw_data${x#/data}"; done' _ {} + 
  • Как использовать подстановочные знаки (*) при копировании с помощью scp?
  • Как удалить все в каталоге?
  • Заказ файлов, открытых программой
  • ограничение нажатия на выбранные репозитории Mercurial с использованием принудительных команд `ssh` и` hg-ssh`
  • tar исключить файлы * .zip
  • Исключить символы для SCP-файла
  • Согласование только числовых расширений файлов
  • Выбирайте только каталоги и порядок с помощью эха
  • Используйте расширенное подтачивание Bash, чтобы свести на нет имя файла, начинающегося с точки
  • Почему 2 машины linux ведут себя по-другому с командой того же синтаксиса?
  • В чем разница между '* .txt' и * .txt?
  • Linux и Unix - лучшая ОС в мире.