3

Учитывая много каталогов / подкаталогов, содержащих много разных типов файлов (csv, txt, jpg и т.д.), Какая команда будет рекурсивно искать каждый каталог и копировать файлы в новый каталог верхнего уровня, названный в честь каждого расширения.

Есть ли способ сделать это с помощью одной строки?

2 ответа2

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
0

Это можно сделать очень просто с помощью команды find, как правильно подсказал Алекс: при условии, что каталог для поиска файлов - /path1/to/some/dir, и вы хотите, чтобы файлы были перемещены в /path2/to/other/dir/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' {} \; 

Эта команда сначала находит все файлы (-type f), содержащиеся в каталоге /path1/to/some/dir и всех его подкаталогах, а затем передает имя каждого такого файла ({}) на небольшой двухслойный bash, который сначала извлекает расширение из имени файла (называемого внутри bash $ 0) и назначает его локальной переменной оболочки MYDIR, затем проверяет наличие подходящего каталога (если такого каталога нет, то, возможно, мы допустили ошибку) , и если каталог существует (&& ...), он перемещает файл в соответствующий каталог, в противном случае (|| ...) он помещает файл в место по умолчанию, /path3/to/miscellanea.

Выше предполагается, что вы уже создали необходимые каталоги, /path2/to/other/dir/txt и так далее. Если вместо этого вы хотите создать их на ходу, вам придется изменить вышеприведенное как:

find /path1/some/dir -type f -exec bash -c 'MYDIR=/path2/to/other/dir/${0##*.}; mkdir -p $MYDIR && mv $0 $MYDIR' {} \; 

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .