* nix One-Liner: рекурсивно знайдіть файли за допомогою розширення та скопіюйте їх у новий каталог, названий для розширення


2

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

Чи є спосіб це досягти однолінійним?


1
Команда, яку потрібно викликати find. Ви можете побудувати його як однолінійний
Алекс

Чому це повинно бути на одній лінії?
Сет

Я думаю, що вони хочуть, щоб команда виконувалася через SSH або щось таке, де сценарій не обов'язково існуватиме в системі призначення.
stuts

Відповіді:


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

Це можна зробити дуже просто за допомогою пошуку , як правильно запропонував Алекс: якщо припустити, що каталог для сканування файлів є / 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' {} \; 

Ця команда спочатку знаходить усі файли ( -типу f ), що містяться в каталозі / path1 / to / some / dir, та всіх його підкаталогах, а потім передає ім'я кожного такого файлу ( {} ) у невеликий двошаровий bash, який спочатку витягує розширення з імені файлу (іменованого $ 0 всередині bash) і призначає його до локальної змінної оболонки MYDIR , потім перевіряє наявність відповідного каталогу (якщо такого каталогу немає, то, можливо, ми помилилися) , а якщо каталог існує ( && ... ), він переміщує файл у відповідний каталог, в іншому випадку ( || ... ) він розміщує файл у місці за замовчуванням, / path3 / до / 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' {} \; 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.