Как я могу использовать xargs для копирования файлов с пробелами и кавычками в именах? - PullRequest
216 голосов
/ 27 сентября 2008

Я пытаюсь скопировать кучу файлов в каталог, и в именах некоторых файлов есть пробелы и одинарные кавычки. Когда я пытаюсь связать вместе find и grep с xargs, я получаю следующую ошибку:

find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote

Есть предложения по более эффективному использованию xargs?

Это на Mac OS X 10.5.3 (Leopard) с BSD xargs.

Ответы [ 21 ]

191 голосов
/ 27 сентября 2008

Вы можете объединить все это в одну команду find:

find . -iname "*foobar*" -exec cp -- "{}" ~/foo/bar \;

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

Примечание. Флаг --, передаваемый cp, не позволяет обрабатывать файлы, начиная с - в качестве параметров.

114 голосов
/ 27 сентября 2008

find . -print0 | grep --null 'FooBar' | xargs -0 ...

Я не знаю, поддерживает ли grep --null, не поддерживает ли xargs -0 на Leopard, но на GNU все хорошо.

76 голосов
/ 04 ноября 2015

Самый простой способ сделать то, что хочет оригинальный постер, это изменить разделитель с любого пробела на символ конца строки, например:

find whatever ... | xargs -d "\n" cp -t /var/tmp
69 голосов
/ 29 сентября 2008

Это более эффективно, так как не запускает "cp" несколько раз:

find -name '*FooBar*' -print0 | xargs -0 cp -t ~/foo/bar
55 голосов
/ 22 августа 2012

Я столкнулся с той же проблемой. Вот как я это решил:

find . -name '*FoooBar*' | sed 's/.*/"&"/' | xargs cp ~/foo/bar

Я использовал sed для замены каждой строки ввода одной строкой, но в двойных кавычках. На странице руководства sed " ... амперсанд (` & & ''), появляющийся при замене, заменяется строкой, соответствующей RE ..."- в данном случае .*, вся линия.

Это решает ошибку xargs: unterminated quote.

50 голосов
/ 28 августа 2013

Этот метод работает на Mac OS X v10.7.5 (Lion):

find . | grep FooBar | xargs -I{} cp {} ~/foo/bar

Я также проверил точный синтаксис, который вы разместили. Это также хорошо работало на 10.7.5.

11 голосов
/ 26 июня 2013

Только не используйте xargs. Это аккуратная программа, но она не подходит для find, когда сталкивается с нетривиальными случаями.

Вот портативное (POSIX) решение, то есть такое, которое не требует find, xargs или cp определенных GNU расширений:

find . -name "*FooBar*" -exec sh -c 'cp -- "$@" ~/foo/bar' sh {} +

Обратите внимание на окончание + вместо более обычного ;.

Это решение:

  • правильно обрабатывает файлы и каталоги со встроенными пробелами, символами новой строки или любыми экзотическими символами.

  • работает в любой системе Unix и Linux, даже в тех, которые не предоставляют инструментарий GNU.

  • не использует xargs, что является хорошей и полезной программой, но требует слишком много настроек и нестандартных функций для правильной обработки find вывода.

  • также более эффективно (читается быстрее ), чем принятые, и большинство, если не все другие ответы.

Обратите внимание, что, несмотря на то, что указано в некоторых других ответах или комментариях, цитирование {} бесполезно (если вы не используете экзотическую оболочку fish).

8 голосов
/ 20 марта 2014

Для тех, кто полагается на команды, кроме find, например, ls:

find . | grep "FooBar" | tr \\n \\0 | xargs -0 -I{} cp "{}" ~/foo/bar
8 голосов
/ 27 сентября 2008

Посмотрите, как использовать параметр командной строки --null для xargs с параметром -print0 в find.

5 голосов
/ 10 февраля 2012
find | perl -lne 'print quotemeta' | xargs ls -d

Я считаю, что это будет работать надежно для любого символа, кроме перевода строки (и я подозреваю, что если в именах файлов есть переводы строк, у вас проблемы хуже, чем этот). Он не требует GNU findutils, только Perl, поэтому он должен работать практически везде.

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