Pull to refresh

Comments 67

Написали же ответ в комментариях, с нормальным решением в одну команду! man rsync.
Мало того, rsync — не единственный способ. Однако, во-первых, он не в входит в стандартную поставку множества дистрибутивов. А во вторых — цель топика не показать одну строчку «как сделать», а рассказать, о том как самому искать решения не изобретая велосипедов.

Или вы думаете что топику не место на хабре?
этому топику — место. исходному — место в QA
этому топику — место
ну скажем так, вроде информация годная, но вот статьёй это назвать тяжело. Это можно свернуть в комментарий к предыдущей «статье», до фразы: «смотри на find и прочитай в man'е, что у cp есть ключ --parents».
а у find есть ключи name и exec. а так же возможность комбинировать ключи через опции -o, -a и скобки. Но кому это интересно?) Читать маны — не модно.
«читаю man'ы — $10, читаю man'ы с выражением — $15» ©
exec, если я не ошибаюсь, есть только в GNU find
-name и ещё -regex, если уж говорить об исходной задаче — укоротили-бы решение, но главной целью было показать возможности конвейера.
Конвейер не предназначен для передачи имён файлов. В ссылке ниже подробное объяснение этому чуду.
exec есть и в POSIX версии. Даже + на конце exec'a там есть, если я не ошибаюсь.
Да, вы правы про exec, видимо у меня сложилось неверное впечатление после того как лет 10 назад я не нашел его в man-e
10 лет прошло — и вот решение найдено :)
UFO just landed and posted this here
UFO just landed and posted this here
$ man cp | grep parents | wc -l
0
Вы правы, это умеет только GNU cp. В комментариях предложили cpio как замену.
Я бы сказал, что это не статья, а часть серии статей о том как писать скрипты. И видя заголовок «как решить то-то», я жду решение, а не экскурс в анализ и знание различных утилит окружения GNU.
Вы знаете, когда я только начинал изучать unix-like системы, главное чему я был поражен — это следование принципу «от понимания к действию» и прочитав одну статью становилось возможным решать весь класс подобных проблем. И этим статьи отличались от «howto» которые как вы и предлагаете — описывали последовательность действий необходимую для достижения конкретного результата в конкретных условиях.

Однако, мне кажется, что хабр уж точно не место для однострочных howto. А эта информация, возможно, поможет кому нибудь понять как решаются такие задачи.
Возможны Вы правы, я обычно изучаю что-либо новое для меня методом индукции. В любом, случае дискуссию на тему «howto vs article» я разводить не хочу.
UFO just landed and posted this here
Боюсь ошибиться, но я много где его не встречал. В ubuntu 10.04 из не-linux — во freebsd.

P.S да, я понимаю, что это решается apt-get install rsync
UFO just landed and posted this here
Если и правда интересно, вечером проведу мини-исследование.
В debian, ubuntu в стандартной поставке он точно отсутствует. Скорее всего в большинстве производных тоже.
пишу из под 10.04, rsync есть.
Отличная статья, познавательная. Спасибо!

На самом деле многому учит.
Для подстановки аргументов ещё можно использовать конструкцию $() внутрь которой мы помещаем файнд с грепом, а всё это целиком отдаём cp в качестве аргумента.
Да, это возможно, но только в bash, а csh, например, это не умеет.
это умеет стандартный шелл
стандартный для какого дистрибутива? у всех могут быть разные «стандартные» шеллы. Даже /bin/sh почти нигде не является тем самым Bourne Shell, а чаще всего ссылкой на /bin/bash или еще куда-то
UFO just landed and posted this here
Полезная инфа, буду знать, спасибо :)
Читать до полного просветления.
Автору исходного поста, кстати, тоже не помешало бы.
А ещё не помешало бы почитать man find и использовать вместо find | grep -v кошерную конструкцию
find /path ! -name "*exclude*"

И вообще, если вы такой противник rsync'a, то задача решается одним find'ом на раз два:
find /path -type f ! -name "*exclude*" -exec cp --parents -t /target/dir "{}" \+


А в целом, в статье я увидел лишь полное нежелание читать маны, стремление использовать странные решения и преподносить это как способ «как самому искать решения не изобретая велосипедов».
Вы правы, в случае, если в качестве исходного списка файлов у нас выступает файловая система — можно использовать find и множество других утилит. Топиком я хотел показать как решать подобный класс задач — комбинированием утилит. Ведь как только мы начинаем брать список файлов, например из файла, find нам уже не поможет.

Вообщем, судя по обилию комментариев с непониманием исходной цели топика, что-то было написано не так и его лучше убрать.
В таком случае, стоило сделать акцент на этом в самом топике. В противном случае тонны конструктивной критики выльются на вас. И комментирующие будут правы.
А в случае чтения списка из файла, стоит тогда включить проверку, есть ли вообще такой файл, и не сломает ли что запускаемая команда.

Вы просто выбрали неудачный пример для того, что хотите продемонстрировать.
Внес изменения в исходный топик, надеюсь этого будет достаточно.
Спасибо за конструктивность.
Если вы хотите что-то продемонстрировать, как то «брать список файлов, например из файла» — так и делайте именно так. Не надо подавать дурных примеров. Те, кто будет это читать, скорее всего не знают о том, что умеет find сам по себе, а стоило бы.
Внес изменения в исходный топик, добавлен дискламер, и готовый рецепт для этой конкретной задачи.

Однако не могли-бы Вы пояснить почему вы считаете использование более универсальных методов дурным примером?
Вы же хотите научить хорошему? Тогда надо учить использовать для каждой задачи подходящий инструмент. Я вполне допускаю, что когда времени нет, лень посмотреть ман, и набрал в консоли первое, что в голову пришло — это одно, но не надо это показывать в качестве обучающего материала. Автор, который осмелился учить чему-то остальных, должен нести большую ответственность.

off
Может быть я брюзжу тут как старый дед =), но уж больно универсалов много развелось, орудующих одним молотком по всем гвоздям, специалистов вот только не найти. И куча how-to в сети только способствует.
Насколько я понял, проблема в том, что очень общую тему я объяснил на примере излишне конкретной задачи.
Думаю, стоит написать отдельный топик, с большим количеством теории и рассмотрев больше примеров, про который нельзя будет сказать что «это решается одной командой». Но так уж получилось, что я собрался написать статью именно в ответ на тот топик.

off reply
Мне кажется, что непрофессионализм, частным случаем которого является поверхностный подход (естественно, подразумевая ситуации, где такой подход не допустим) — является скорее свойством личности, а не результатом неправильного обучения
Никогда не понимал, что означает конструкция
"{}" \+
в конце find-а?
Очень полезная штука. find с \; запускает по одному процессу на каждый найденный файл. find с \+ на конце группирует файлы и запускает по одному процессу на много файлов. Экономия времени и ресурсов, однако. Появилась лет 7 назад.

С вас 10$ за краткую выжимку из man'а =)
UFO just landed and posted this here
Но ведь за каждое использование пайпа там, где без него можно обойтись, бог будет убивать котенка.
Экий вы бездушный
UFO just landed and posted this here
Но в священном писании говорится про каждого котенка за каждый проход пайпа. Не несите ересь.
man find говорит нам, что:
Строка `{}' будет заменена именем текущего обрабатываемого файла

У меня этот вариант работает и без слеша. Но безопаснее/привычнее экранировать.

Вообще есть 2 варианта запуска find -exec:
find -exec echo {} ;
find -exec echo {} +


Попытка скопировать это и выполнить в шелле провалится, т.к. шелл съест «; ». Чтоб символ дошёл до find, его экранируют от шелла слешем.

Ещё можно взять в кавычки с тем же эффектом:
find -exec echo {} ';'
Спасибо всем за справку.
Вместо 'xargs cp --parents' можно использовать 'cpio -pd'
Необязательно писать find ./, достаточно find .. Меньше набирать, и выглядит красивее.
Да, это привычка, да и кнопки всё равно рядом находятся.
Годная статья. Спасибо.
Как раз недавно задавался подобным вопросом.
Вообще надо будет ознакомиться и начать использовать такие true-юниксойдные штуки, как sed, awk, xargs, find, for, узнать больше о любимом grep. :) Отпугивает то, что выглядит всё это по-шамански сложно.
Пожалуйста.
Не бойтесь, главное преимущество этого подхода то, что каждая отдельная утилита достаточно проста.
Ваш любимый grep выполняет одну функцию — фильтрует. Просто делает он это кучей разных способов, но вам-же не обязательно изучать их все сразу — просто имейте ввиду что grep может отфильтровать всё что угодно, а конкретные параметры всегда можно посмотреть в man в тот момент, когда они понадобятся.
А у меня есть файлы с переводами строк в именах (да, перевод строки — допустимый символ). Как там grep отработает? Подсказываю: неправильно :)
Значит вам, очевидно, нужно будет использовать способы отличные от описанного в основной части топка. Например — один из готовых рецептов в заключении.
Я к этому и веду, что стоит написать, что всё это хорошо, но неверно. А сейчас написано «Задача решена», как будто это верное решение. А в заключении эквивалентное решение.
Вы правы, исправил формулировку.
На самом деле тема многострочной фильтрации не сказать, что хорошо раскрыта. На последнюю задачу выковыривания данных из постраничного вывода я убил приличное количество времени, а от переводов избавлялся с помощью tr`а, что ну никак нельзя назвать элегантным решением. Был бы рад увидеть обзорную статью на эту тему, например. Начинание то у вас хорошее.
Если сильно хочется использовать grep, то тогда нужно в качестве разделителя использовать нулевой символ (гарантировано не часть имени файла).
find . -type f -print0 | grep -z -v 2 | xargs -0 ...

Такой вариант будет правильным. Может, iamwizard будет тоже интересно.
Как уже писалось выше, имхо, эта информация излишня для статьи ориентированной на новичков.
Думаю, что этот и другие интересные варианты решения найдут себе место в более цикле статей ориентированном на более подготовленную публику.
Если найду время написать, то обязательно затрону тему сепараторов и экранирования
Декомпозиция требует первым делом выписать все файлы, а спасает от первичного формирования громадной простыни юниксовая потоковость команд, да? Без возможности организовать поток такой подход был бы чреват неэффективным использованием ресурсов, для предварительного формирования того огромного списка…
«Получить список файлов» и «Получить список всех файлов» — это разные вещи, а итеративность возможно организовать и в отсутствии пайпа.
некогда озаботился проблемой сложного копирования файлов, пробовал xcopy, robocopy итп и пришел к выводу что во многих ситуациях нужно писать скрипт. Тогда сел и в качестве развлечения написал свою консольную программку для копирования. Основной фишкой которой было разделение ключей для копирования на ключи для файлов и пля папок. Так же реализовал возможность задания множества масок для каждого ключа. С тех пор перестал пользоваться вышеуказанными утилитами и по мере нужды добавляю в свою прогу новые возможности. На данный момент уже получился хороший список, и точно могу сказать, то что в этой проге можно сделать одним запуском проги в других, без написания скрипта не получится. Кому интересно тут последняя альфа. Если кому что то надо добавить обращайтесь.
маленький пример:
copymik "c:\Папка откуда" "d:\Папка куда" /MF *.txt *.doc *.pdf /MD Doc* Scan /XCF __*.pdf bak*.doc ~*.pdf /XCD Temp Tmp
скопирует файлы с масками *.txt *.doc *.pdf исключив файлы с масками __*.pdf bak*.doc ~*.pdf из папок с масками Doc* Scan пропуская в них папки с масками Temp Tmp
где:
Заголовок спойлера
[/MF[ МаскаФайла1[ МаскаФайла2[ ....]]]] Маска для копирования файлов (по умолчанию маска * — все)
[/MD[ МаскаПапки1[ МаскаПапки2[ ....]]]] Маска для копирования папок (по умолчанию маска * — все)
[/XCD [МаскаПапки1[ МаскаПапки2[ ....]]]] Не копировать папки с указанными масками (по умолчанию маска * — все)
[/XCF [МаскаФайла1[ МаскаФайла2[ ....]]]] Не копировать файлы с указанными масками (по умолчанию маска * — все)


если надо перезаписать то добавить /OF
если в каких то папках ненадо проверять маски файлов то /XDMF или /XDMD
Заголовок спойлера
[/XDMD МаскаПапки1[ МаскаПапки2[ ....]]] Не проверять маску папки для подпапок с указанной маской (будет использована маска * — все)
[/XDMF МаскаПапки1[ МаскаПапки2[ ....]]] Не проверять файловую маску для подпапок с указанной маской (будет использована маска * — все)

и.т.п
в этой программке Вас многое, надеюсь приятно, удивит

Ребята подскажите как мне исправить.
find /home/vmail/vp/cur/ -type f -exec grep -H "To: office@vp.com" {} \; | xargs -n 1 -I % cp --parents "%" /home/OFFICE/

У меня в результате находит файл но при копировании подставляет «To: office@vp.com». А как сделать так что бы подставляло только пусть?
сам нашел ответ. ключ -l в grep выводит тольк имя файла
Sign up to leave a comment.

Articles