LINUX.ORG.RU

Поиск типа файлов и применение к ним действия в терминале...

 , , ,


1

2

Есть несколько папок. В папках куча файлов с разным расширением. Хочу через терминал сделать отбор файлов и копирование/перемещение их в отдельную папку. Например, файлы, оканчивающиеся на .jpeg нужно будет скопировать/переместить в папку JPEGS, а файлы с .docx в папку DOCXS и т.д. Подозреваю, что это можно сделать при помощи find и xargs, но как?

zsh:

cp **/*.jpeg JPEPGS/
cp **/*.docx DOCXS/
Или суффиксы заранее неизвестны и тебе надо обработать вообще все файлы?

x3al ★★★★★
()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от x3al

ну, если ещё будет сортировка по суффиксам (расширениям), то вообще было бы шикарно!

Desmond_Hume ★★★★★
() автор топика
Ответ на: комментарий от Desmond_Hume

А почему две звёздочки (**/*)? Опечатка или такой синтаксис?

Потому, что рекурсивный глоббинг.

ну, если ещё будет сортировка по суффиксам (расширениям), то вообще было бы шикарно!

zsh:

for i in **/*; do basename=`basename $i`; cp "$i" ${${basename##*.}:u}S/; done
Это пройдётся по всем файлам и рассортирует по суффиксам. Структура директорий не сохраняется, всё кидается в корень, при дублирующемся имени все файлы кроме первого игнорируются.

UPD: чёрт, давно же не писал на zsh. нафиг не нужно basename, можно builtins.

for i in **/*; do basename=${i:t}; cp "$i" ${${basename##*.}:u}S/; done

x3al ★★★★★
()
Последнее исправление: x3al (всего исправлений: 4)
Ответ на: комментарий от Desmond_Hume
shopt -s globstar

и баш научится понимать **/*. Но я хз, как заставить его понимать zsh-style substitutions и мне лень читать ман. sed'ом выкусить расширение, может.

x3al ★★★★★
()

Есть несколько папок.

Допустим, что их зовут /path/to/folder1, /path/to/folder2 и т. п., тогда

find /path/to/folder1 /path/to/folder2/ \( -name \*.jpeg -type f -exec mv -t /path/to/JPEGS '{}' + \) -o \( -name \*.docx -type f -exec mv -t /path/to/DOCXS '{}' + \) -o \( -name \*.foobar -type f -exec mv -t /path/to/FOOBARS '{}' + \)

. Относительные пути также допустимы. Ответ дан в предположении, что у mv есть ключ -t (у POSIX mv его нет, у древнего GNU mv тоже).

dexpl ★★★★★
()
Ответ на: комментарий от Desmond_Hume

Даже не рабочие заготовки, а рабочий и испытанный временем скрипт для разбора завалов в каталоге с загрузками.

Bfgeshka ★★★★★
()
Ответ на: комментарий от x3al

выкусить расширение, может.

bash

n='aaaa.bbb.ccc'

$ echo ${n%%.*}
aaaa

$ echo ${n%.*}
aaaa.bbb

$ echo ${n#*.}
bbb.ccc

$ echo ${n##*.}
ccc
anonymous
()
Ответ на: комментарий от Bfgeshka

удобочитаемость и лёгкость редактирования стоит перед оптимизациями

".*\.(jpg|jpeg)$"

это нагляднее '*.jpg'? Или ты что другое имел в виду?

anonymous
()
Ответ на: комментарий от anonymous

Имелось в виду то, что при бОльшем количестве расширений файла проще их все увидеть сразу.

То есть (doc|docx|rtf|odt) проще распарсить человеку, чем кучу ключей. Для одного-двух расширений отдельные -name в самый раз.

Bfgeshka ★★★★★
()

Кстати, не многие применяют на практике такой прием:

updatedb

locate '/path/to/dir/*.jpg' | xargs mv -t /path/to/jpgs/ 
поддиректории /path/to/dir/ тоже попадут под шаблон '/path/to/dir/*.jpg'

Диск не насилуется множеством find'ов
anonymous
()
Ответ на: комментарий от Bfgeshka

Может и так, но в реальной жизни будут либо множество простых запусков либо подобный скрипт с простыми find

for EXT in jpg:JPEGS jpeg:JPEGS  doc:DOCS docx:DOCS do
  ext=${EXT%:*}  # jpg
  dir=${EXT#*:}  # JPEGS
  find $STARTPATH -type f -name \*.$ext -exec mv {} $MOVEPATH/$dir \;
done
anonymous
()
Ответ на: комментарий от x3al

man «старого пса новым фокусам не научишь»

zolden ★★★★★
()
Ответ на: комментарий от x3al

Почему все предпочитают find, а не глоббинг?

можешь рассказать как работает механизм глоббинга? что будет при очень большом кол-ве файлов и какова его эффективность по сравнению со старым find'ом?

anonymous
()
Ответ на: комментарий от anonymous

что будет при очень большом кол-ве файлов

Если напрямую закидывать его аргументом (cp /path/to/**/*), то фигово. Если в for i in **/*, то ок.

какова его эффективность по сравнению со старым find'ом?

Хз. но как минимум оно позволяет решить некоторые задачи целиком в builtins и пользоваться ими напрямую (в выражениях find такое нельзя, будет запускаться процесс шелла в лучшем случае).

x3al ★★★★★
()
Ответ на: комментарий от x3al

Если напрямую закидывать его аргументом (cp /path/to/**/*), то фигово. Если в for i in **/*, то ок.

Еще есть zargs.

salsa
()
Ответ на: комментарий от x3al
$ time bash -c 'shopt -s globstar; i=0; cd /; for x in **/*; do i=$((i+1)); done; echo $i'

814409

real	0m39.829s
user	0m34.320s
sys	0m5.356s

$ time bash -c 'shopt -s globstar; i=0; cd /; for x in **/*; do i=$((i+1)); done; echo $i'

815174

real	0m41.650s
user	0m36.368s
sys	0m5.116s

$ time find / 2>/dev/null | wc -l

800953

real	0m4.300s
user	0m0.708s
sys	0m1.388s

$ time find / 2>/dev/null | wc -l
800046

real	0m1.551s
user	0m0.636s
sys	0m1.072s

Спасибо, уж лучше форкнуть find

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.