1

Здравствуйте.
Нужен способ перемещения файлов, соответствующих набору масок с регулярными выражениями, из одной директории в другую, причем рекурсивно и с сохранением структуры папок. В винде это делается очень удобно в TotalCommander командой переместить. В Линуксе (Debian 5) это стало проблемой. Попробовал Krusader, Gnome Commander и Tux Commander, но в них такой опции нет.
Пока лучшее что получилось - сделать такой скрипт:

#! /bin/sh
find $1 -name "*.v21.log" -o -name "*.v22.log" -o -name "*.v23.log" -o -name "*.aver.log" -exec mv {} $2 \;

Но не создается структура каталогов исходной папки. Опций таких я не нашел. Посоветуете что-нибудь?

2

Можно пояснить на примере, что именно требуется?

"Если вы уже пытались поработать с Linux, но нашли ее слишком запутанной и непонятной — расслабьтесь. Если вы умеете вскипятить чайник или завести будильник, то вы уже можете стать пользователем Linux (кроме шуток!)." ©

3

NordWest пишет:

Опций таких я не нашел. Посоветуете что-нибудь?

эх... есть такая опция. называется она... никак она не называется ab

 Консоль:
$ cp -Rv z dd
«z» -> «dd/z»
«z/send-spam» -> «dd/z/send-spam»
«z/spam-adr.txt» -> «dd/z/spam-adr.txt»
«z/1  3» -> «dd/z/1  3»
«z/file_list» -> «dd/z/file_list»
«z/tttt.txt» -> «dd/z/tttt.txt»
«z/inodes» -> «dd/z/inodes»
«z/1   2» -> «dd/z/1   2»
«z/fp.c» -> «dd/z/fp.c»
«z/1» -> «dd/z/1»
«z/message» -> «dd/z/message»
«z/fp» -> «dd/z/fp»

не то?

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

4

а с find будет так:

 Консоль:
$ find -regex '.*1.*' -print0 | xargs -0 cp --parents -Rv -t a
«./1  3» -> «a/./1  3»
«./1   2» -> «a/./1   2»
./dd -> a/./dd
./dd/z -> a/./dd/z
«./dd/z/1  3» -> «a/./dd/z/1  3»
«./dd/z/1   2» -> «a/./dd/z/1   2»
«./dd/z/1» -> «a/./dd/z/1»
./dd/z/zzz -> a/./dd/z/zzz
«./dd/z/zzz/1  3» -> «a/./dd/z/zzz/1  3»
«./dd/z/zzz/1   2» -> «a/./dd/z/zzz/1   2»
«./dd/z/zzz/1» -> «a/./dd/z/zzz/1»
«./1» -> «a/./1»
./z -> a/./z
«./z/1  3» -> «a/./z/1  3»
«./z/1   2» -> «a/./z/1   2»
«./z/1» -> «a/./z/1»

оно?

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

5

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

 Консоль:
$ find -regex '.*1.*' ! -regex "\./a/.*" -delete

PS: настоятельно рекомендую прочитать man regex
ну и man cp конечно...

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

6

NordWest пишет:

-name "*.v21.log" -o -name "*.v22.log" -o -name "*.v23.log" -o -name "*.aver.log"

-regex '.*\.\(v2[123]\|aver\)\.log'

не?

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

7 (17.03.2011 11:59:04 отредактировано NordWest)

Спасибо за ответы. Что-то никак с подпиской на темы не разберусь, только сегодня увидел отклики.

В общем, добиться нужного результата получилось таким вот образом:

find $1 -regex '.*\.\(v2[123]\|aver\)\.log' -exec cp --parents -Rv {} $2 \;
find $1 -regex '.*\.\(v2[123]\|aver\)\.log' -delete

Т.е. сначала копируется с созданием в целевой папке $2 структуры каталогов, за что спасибо --parents похоже. А вторым действием ищутся те же файлы и удаляются. В принципе, если добавить к cp ключ -f, то потери данных опасаться не стоит. Может и не очень изящно, но работает. Большое спасибо!


А вот ещё вопрос. find придется запускать из директории $1 и тут возникает опасность с относительными путями в $1 и $2. Как можно перевести относительный путь в абсолютный?

8

NordWest пишет:

Как можно перевести относительный путь в абсолютный?


 Консоль:
$ readlink -f ../../disk-1/slax/
/media/disk-1/slax

не забывайте заключать переменные в "двойные кавычки", а параметры без переменных в 'одиночные'

а то наступите на такие грабли:

 Консоль:
root@ksu:/media/disk/Music/1988# /bin/ls 1988-05*
1988-05 - Один день Ивана Денисовича.mp3
root@ksu:/media/disk/Music/1988# N=`/bin/ls 1988-05*`
root@ksu:/media/disk/Music/1988# ls $N
/bin/ls: невозможно получить доступ к 1988-05: Нет такого файла или каталога
/bin/ls: невозможно получить доступ к -: Нет такого файла или каталога
/bin/ls: невозможно получить доступ к Один: Нет такого файла или каталога
/bin/ls: невозможно получить доступ к день: Нет такого файла или каталога
/bin/ls: невозможно получить доступ к Ивана: Нет такого файла или каталога
/bin/ls: невозможно получить доступ к Денисовича.mp3: Нет такого файла или каталога

как видите, shaell разрезала имя файла с пробелами так, что команда поняла это не как одно имя, а как несколько.
а вот так работает

 Консоль:
root@ksu:/media/disk/Music/1988# ls "$N"
1988-05\ -\ Один\ день\ Ивана\ Денисовича.mp3*

NordWest пишет:

за что спасибо --parents похоже.

--parents просто копирует не файл x.txt, а файл ./dir/x.txt
получается, что копируется файл target/./dir/x.txt или, что тоже самое target/dir/x.txt, ибо точка - это другое имя этого-же каталога (хардлинк).

Кстати, точка именно для этого и применяется.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

9 (13.04.2011 10:07:47 отредактировано NordWest)

В результате оказалось на много проще и удобнее установить TotalCommander под wine. Как то сразу идея не пришла в голову почему-то. Он там с перезаписью правда что-то мутит, но всё равно лучше чем скриптами заморачиваться. Ну зато со скриптами кое-какие вопросы с вашей помощью разобрал, тоже польза.

10

NordWest пишет:

В результате оказалось на много проще и удобнее установить TotalCommander под wine.

хороший костыль на первое время ab

NordWest пишет:

но всё равно лучше чем скриптами заморачиваться.

такие вопросы решаются простым одностроком. вот только я не очень понимаю, ЗАЧЕМ вообще решать такую задачу? если это часть скрипта - то скриптом таки проще. А именно как вы пишете - облазить каталоги, найти файлы, а потом их копировать ещё и с сохранением... Есть ещё один путь:

 Консоль:
( cd dir1; tar -cf - --exclude MASK * ) | ( cd dir2; tar -xf - )

это переносит(точнее копирует) файлы из dir1 в dir2. Сам архив нигде никогда не сохраняется, т.ч. не бойтесь, я так сотни гигов переносил.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

11

Позвольте снова затронуть тему. Появилось более существенное применение подобного скрипта.
Значит у меня есть директория с подпапками и файлами, которые требуется переместить.
Т.е.:
/path2inidir/folder01/file1.arj
/path2inidir/folder01/file2.arj
/path2inidir/folder02/file1.arj
/path2inidir/folder02/file2.arj

Мне нужно переместить только файлы с расширением dat1 в другую папку /path2resdir с сохранением структуры:
/path2resdir/folder01/file1.arj
/path2resdir/folder01/file2.arj
/path2resdir/folder02/file1.arj
/path2resdir/folder02/file2.arj

Если я делаю так:

find $1 -regex '.*\(average\|raw\)\.arj' -exec cp --parents -rv {} $2 \;

То он создает такую структуру папок:
/path2resdir/path2inidir/folder01/file1.arj
...

Пробовал этот вариант:

 Консоль:
( cd dir1; tar -cf - --exclude MASK * ) | ( cd dir2; tar -xf - )

Но тут не понятно как с маской быть. Указать *.arj *, так он мне arj мои и исключит. Там ключа --include нет случаем? Я в описании не нашел.

12 (14.07.2011 23:36:47 отредактировано NordWest)

Получилось! ab
Уверен, что очень криворуко, и есть более простой вариант, но работает.

#!/bin/bash
for file in `find $1 -regex '.*\(average\|raw\)\.arj' -print`
do 
DIR=$2${file#$1}
DIR=${DIR%/*}
mkdir -p $DIR
cp -R ${file}  $DIR
done

Жаль, что в винде это делается одной командой.

xcopy %1*.arj %2 /E/Y

13

NordWest пишет:

Жаль, что в винде это делается одной командой.

ac  ah

 Консоль:
$ cp -v --parent **/*p.png target/

+ открыть спойлер

 Консоль:

common -> target/common
common/extensions -> target/common/extensions
common/extensions/docs -> target/common/extensions/docs
common/extensions/docs/images -> target/common/extensions/docs/images
common/extensions/docs/images/index -> target/common/extensions/docs/images/index
«common/extensions/docs/images/index/html5app.png» -> «target/common/extensions/docs/images/index/html5app.png»
common/extensions/docs/images/overview -> target/common/extensions/docs/images/overview
«common/extensions/docs/images/overview/browser-action-with-popup.png» -> «target/common/extensions/docs/images/overview/browser-action-with-popup.png»
«common/extensions/docs/images/overview/flash-app.png» -> «target/common/extensions/docs/images/overview/flash-app.png»
d3 -> target/d3
d3/d4 -> target/d3/d4
d3/d4/app -> target/d3/d4/app
d3/d4/app/theme -> target/d3/d4/app/theme
«d3/d4/app/theme/back_p.png» -> «target/d3/d4/app/theme/back_p.png»
«d3/d4/app/theme/browser_action_p.png» -> «target/d3/d4/app/theme/browser_action_p.png»
«d3/d4/app/theme/browser_actions_overflow_p.png» -> «target/d3/d4/app/theme/browser_actions_overflow_p.png»
«d3/d4/app/theme/browser_actions_overflow_win_p.png» -> «target/d3/d4/app/theme/browser_actions_overflow_win_p.png»
«d3/d4/app/theme/close_bar_p.png» -> «target/d3/d4/app/theme/close_bar_p.png»
«d3/d4/app/theme/download_button_center_bottom_p.png» -> «target/d3/d4/app/theme/download_button_center_bottom_p.png»
«d3/d4/app/theme/download_button_center_middle_p.png» -> «target/d3/d4/app/theme/download_button_center_middle_p.png»
«d3/d4/app/theme/download_button_center_top.png» -> «target/d3/d4/app/theme/download_button_center_top.png»

hint:

 Консоль:
$ shopt globstar
globstar           on

NordWest пишет:

Пробовал этот вариант:
Консоль:

( cd dir1; tar -cf - --exclude MASK * ) | ( cd dir2; tar -xf - )

Но тут не понятно как с маской быть. Указать *.arj *, так он мне arj мои и исключит. Там ключа --include нет случаем? Я в описании не нашел.

эх...

звёздочку меняйте на **/*{average,raw}.arj

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

14 (21.07.2011 10:44:26 отредактировано drBatty)

и да, man bash

man bash пишет:

              globstar
                      If  set, the pattern ** used in a pathname expansion context will match a files and zero or
                      more directories and subdirectories.  If the pattern is followed by a /,  only  directories
                      and subdirectories match.

info coreutils 'cp invocation'

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

15

NordWest пишет:

xcopy %1*.arj %2 /E/Y

а как **/*{average,raw}.arj  ae

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

16

drBatty пишет:

hint:

У меня "globstar off".

Если перейти в папку, из которой нужно копировать, то это сработает:

 Консоль:
$ cp -v --parent **/*.arj target/

Если без перехода и с путем к исходной папке, так например:

 Консоль:
$ cp -v --parent $1**/*.arj target/

Будет снова "/path2resdir/path2inidir/folder01/file1.arj"
Конечно можно переходить -> копировать -> возвращаться.

17

NordWest пишет:

У меня "globstar off".

дык сделайте on.
hint: help shopt

NordWest пишет:

то это сработает:

нет.
подкаталоги не пойдут.

NordWest пишет:

cp -v --parent $1**/*.arj target/

 Консоль:
( cd "$1" && cp -v --parent **/*.arj target/ )

не?
ВСЕ операции в Linux выполняются в рабочем каталоге. Управлять рабочим каталогом из какого-то левого - ИМХО маздайный бред. Кстати, в TC&NC тоже есть текущий каталог.

PS: внутри скрипта скобки не нужны:

#!/bin/bash
shopt -s globstar
cd "$1"
cp -v --parent **/*.arj target/
Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

18 (21.07.2011 17:54:13 отредактировано Fat-Zer)

а если что-то подобное соорудить:

 Консоль:
#!/bin/bash
find <фильтр> | while read FILE; do
    TARGET_FILE_DIR="${TARGET_DIR}/$(echo ${FILE}| sed -e 's!\(.*/\).*$!\1!')"
    mkdir -p $TARGET_FILE_DIR
    cp FILE $TARGET_FILE_DIR
done

95% процентов проблем находятся между клавиатурой и стулом.

19

Fat-Zer пишет:

а если что-то подобное соорудить:

а зачем?

Кстати, sed тут во первых неправильно применяется, во вторых просто не нужна.
Как и вся та строчка.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

20 (21.07.2011 17:53:39 отредактировано Fat-Zer)

drBatty пишет:

а зачем?

не знаю... мне так нравится...

drBatty пишет:

Кстати, sed тут во первых неправильно применяется, во вторых просто не нужна.

нуда... скобки забыл... fixed...
как без него?

drBatty пишет:

Как и вся та строчка.

о_О

95% процентов проблем находятся между клавиатурой и стулом.

21

Fat-Zer пишет:

нуда... скобки забыл... fixed...
как без него?

вообще-то путь выделяется без слеша. Так проще потом с ним работать.

 Консоль:
ksu@ksu:~$ NAME="/a/b/c/d/e/file"
ksu@ksu:~$ echo "${NAME%/*}"
/a/b/c/d/e

не написал раньше потому, что не знал, что вы хотите сделать (без скобок непонятно)
выделить имя файла можно так:
 Консоль:
ksu@ksu:~$ echo "${NAME##*/}"
file

Ну и конечно
 Консоль:
ksu@ksu:~$ basename "$NAME"
file
ksu@ksu:~$ dirname "$NAME"
/a/b/c/d/e

ЗЫЖ в первом варианте $TARGET_FILE_DIR не использовалась.

ЗЗЫЖ ответ на вопрос "зачем?" будет ясен после того, как вы сравните скорость моего и своего варианта хотя-бы даже на сотне файлов и каталогов.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

22

drBatty пишет:

Ну и конечно

не знал про такое, спасибо...

drBatty пишет:

ответ на вопрос "зачем?" будет ясен после того, как вы сравните скорость моего и своего варианта хотя-бы даже на сотне файлов и каталогов.

согласен... скорость в разы медленнее будет...

95% процентов проблем находятся между клавиатурой и стулом.

23

Fat-Zer пишет:

скорость в разы медленнее будет...

дык зачем тут вообще какие-то скрипты, если cp отлично справляется?

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

24

drBatty пишет:

дык зачем тут вообще какие-то скрипты, если cp отлично справляется?

на случай если нужно ещё какое-то хитрое переименование... правда тогда лучше всё в аргументы find упихнуть...

95% процентов проблем находятся между клавиатурой и стулом.

25 (22.07.2011 10:42:43 отредактировано drBatty)

Fat-Zer пишет:

на случай если нужно ещё какое-то хитрое переименование... правда тогда лучше всё в аргументы find упихнуть...

в этих случаях я использую что-то вроде
find УСЛОВИЕ -printf ФОРМАТ | sed ...

PS:
или

find ... >file.list

sed -i '' file.list

while read NAME; do
действие
done <file.list

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

26

Спасибо, вариантов с копированием действительно предостаточно. А вот с перемещением как? У mv нет ключа --parents. Его можно использовать для в накрученном скрипте, где и cp без --parents. Можно было бы копировать и потом удалять, но нет гарантий, что это будет один и тот же список файлов. Или есть какая-то хитрая штука у того же mv, которая скопирует структуру каталога?

27

Сижу читаю топик, фраза "перемещение" и здесь же

NordWest пишет:

которая скопирует структуру каталога?

может вас rsync спасет?  oO

It is good day to die ...
MS Windows 10
Заметки о главном...

28

rsync спасет мир, но не в этом случае ab

i2ks пишет:

Сижу читаю топик, фраза "перемещение" и здесь же

Не вижу противоречия. Перемещение - это копирование + удаление скопированного файла.

29

NordWest пишет:

А вот с перемещением как?

а перемещение это довольно опасная операция. не советую её использовать...

NordWest пишет:

Или есть какая-то хитрая штука у того же mv, которая скопирует структуру каталога?

не знаю. это не нужно ИМХО.

NordWest пишет:

Перемещение - это копирование + удаление скопированного файла.

а вот и нет. точнее да, но только в том случае, если вы перемещаете в разных ФС. Если в одной и той-же, то mv эт
создание другого имени у файла + удаление старого имени. Можете проверить - в этом случае не нужно даже права чтения файла, достаточно права модификации каталога где источник + права добавления к каталогу-приёмнику.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

30 (15.05.2014 16:43:04 отредактировано iamkaant)

drBatty пишет:

 Консоль:
$ cp -v --parent **/*p.png target/

Специально зарегился, чтобы спасибо сказать. ab
И спасибо за указание того, что shopt нужно использовать, сам бы не разобрался.

 Консоль:
shopt -s globstar