
Учитывая, что существует множество каталогов/подкаталогов, содержащих множество различных типов файлов (csv, txt, jpg и т. д.), какая команда будет рекурсивно искать в каждом каталоге и копировать файлы в новый каталог верхнего уровня, названный в честь каждого расширения?
Есть ли способ сделать это с помощью одной строки?
решение1
Решение
Следующая команда выведет список всех файлов в текущем каталоге ( .
) и переместит их в каталоги, названные по их расширениям в ./OUTPUT
:
for file in $(find . -type f) ; do EXTENSION=$(echo "$file" |sed 's/.*\.//g') ; rsync -av $file ./OUTPUT/$EXTENSION/ ; done
Перед выполнением указанной выше команды вам необходимо:
- Создать каталог OUTPUT в текущем каталоге (
mkdir OUTPUT
) - Убедитесь, что ни в одном из подкаталогов нет файлов с совпадающими именами.
Объяснение
Во-первых, цикл присваивает переменной file
файл из вывода find . -type f
. Пример вывода команды find
приведен ниже:
./a/myfile1.zip
./a/b/adoc1.txt
./a/b/adoc2.txt
./a/b/adoc3.txt
./a/b/adoc4.txt
./a/myfile3.zip
./a/myfile4.zip
./a/myfile2.zip
Переменная EXTENSION
создается, и ее значением является file
переменная, в которой удалено все до последней точки. Так что это ./a/myfile1.zip
станет zip
.
Затем файл синхронизируется (с подробностями v
) с каталогом, OUTPUT
названным по расширению файла.
Пример моего файлового дерева после запуска этой команды в некотором тесте:
./a
./a/b
./a/b/adoc1.txt
./a/b/adoc2.txt
./a/b/adoc3.txt
./a/b/adoc4.txt
./a/b/c
./a/myfile1.zip
./a/myfile2.zip
./a/myfile3.zip
./a/myfile4.zip
./b
./b/c
./b/c/d
./b/c/file1.txt
./b/c/file2.txt
./b/c/file3.txt
./b/c/file4.txt
./c
./c/d
./c/d/e
./c/d/e/afile1.rar
./c/d/e/afile2.rar
./c/d/e/afile3.rar
./c/d/e/afile4.rar
./OUTPUT
./OUTPUT/rar
./OUTPUT/rar/afile1.rar
./OUTPUT/rar/afile2.rar
./OUTPUT/rar/afile3.rar
./OUTPUT/rar/afile4.rar
./OUTPUT/txt
./OUTPUT/txt/adoc1.txt
./OUTPUT/txt/adoc2.txt
./OUTPUT/txt/adoc3.txt
./OUTPUT/txt/adoc4.txt
./OUTPUT/txt/file1.txt
./OUTPUT/txt/file2.txt
./OUTPUT/txt/file3.txt
./OUTPUT/txt/file4.txt
./OUTPUT/zip
./OUTPUT/zip/myfile1.zip
./OUTPUT/zip/myfile2.zip
./OUTPUT/zip/myfile3.zip
./OUTPUT/zip/myfile4.zip
решение2
Это можно сделать очень просто с помощьюнаходить, как правильно предположил Алекс: предположим, что каталог для сканирования файлов - это/путь1/к/какой-то/директории, и вы хотите переместить файлы в/путь2/к/другой/директории/txtи так далее,
find /path1/some/dir -type f -exec bash -c 'MYDIR=/path2/to/other/dir${0##*.}; [ -d $MYDIR ] && mv $0 $MYDIR || mv $0 /path3/to/miscellanea' {} \;
Эта команда сначала находит все файлы (-тип f) содержится в каталоге/путь1/к/какой-то/директориии все его подкаталоги, затем передает имя каждого такого файла ({}) в небольшую двухстрочную программу bash, которая сначала извлекает расширение из имени файла (называется$0внутри bash) и присваивает его локальной переменной оболочкиМЫДИР, затемтестына предмет наличия подходящего каталога (если такого каталога нет, то, возможно, мы ошиблись), а также, если каталог существует (&& ...) он перемещает файл в соответствующий каталог, в противном случае (||...) он помещает файл в место по умолчанию,/path3/to/разное.
Вышеизложенное предполагает, что вы уже создали необходимые каталоги,/путь2/к/другой/директории/txtи т. д. Если вместо этого вы хотите создавать их на ходу, вам придется изменить вышеприведенное следующим образом:
find /path1/some/dir -type f -exec bash -c 'MYDIR=/path2/to/other/dir/${0##*.}; mkdir -p $MYDIR && mv $0 $MYDIR' {} \;