Почему find -exec mv {} ./target/ + не работает? - PullRequest
95 голосов
/ 10 апреля 2011

Я хочу точно знать, что делают {} \; и {} \+ и | xargs ....Пожалуйста, уточните это с пояснениями.

Ниже 3 команд выполняются и выдают одинаковый результат, но первая команда занимает немного времени, и формат также немного отличается.

find . -type f -exec file {} \;
find . -type f -exec file {} \+
find . -type f | xargs file

Это потому, что 1-й запускает команду file для каждого файла, поступающего из команды find.Итак, в основном это выглядит так:

file file1.txt
file file2.txt

Но последние 2 находят с -exec командами запустить команду файла один раз для всех файлов, как показано ниже:

file file1.txt file2.txt

Затем я запускаю следующие командына котором первый работает без проблем, а второй выдает сообщение об ошибке.

find . -type f -iname '*.cpp' -exec mv {} ./test/ \;
find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ #gives error:find: missing argument to `-exec'

Для команды с {} \+ он выдает мне сообщение об ошибке

find: missing argument to `-exec'

Почему это так?Может кто-нибудь объяснить, что я делаю не так?

Ответы [ 4 ]

181 голосов
/ 10 апреля 2011

Страница руководства (или онлайн-руководство GNU ) в значительной степени объясняет все.

команда find -exec {} \;

Для каждого результата выполняется command {}. Все вхождения {} заменяются именем файла. ; начинается с косой черты, чтобы оболочка не могла его интерпретировать.

команда find -exec {} +

Каждый результат добавляется к command и выполняется впоследствии. Принимая во внимание ограничения на длину команды, я думаю, что эту команду можно выполнить несколько раз, при этом страница справки поддерживает меня:

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

Обратите внимание на эту цитату со страницы руководства:

Командная строка создается так же, как xargs создает свои командные строки

Именно поэтому между {} и + запрещены символы, кроме пробелов. + заставляет find обнаружить, что аргументы должны быть добавлены к команде, как xargs.

Решение

К счастью, реализация GNU mv может принимать целевой каталог в качестве аргумента, либо с -t, либо с более длинным параметром --target. Его использование будет:

mv -t target file1 file2 ...

Ваша find команда становится:

find . -type f -iname '*.cpp' -exec mv -t ./test/ {} \+

со страницы руководства:

-exec команда;

Выполнить команду; true, если возвращается 0 статус. Все последующие аргументы для поиска принимаются в качестве аргументов команды до аргумента, состоящего из `; ' встречается. Строка `{} 'заменяется текущим именем файла, которое обрабатывается везде, где оно встречается в аргументах команды, а не только в аргументах, где он один, как в некоторых версиях find. Обе эти конструкции, возможно, должны быть экранированы (с `\ ') или заключены в кавычки, чтобы защитить их от расширения оболочкой. В разделе ПРИМЕРЫ приведены примеры использования опции -exec. Указанная команда запускается один раз для каждого соответствующего файла. Команда выполняется в начальном каталоге. Существуют неизбежные проблемы безопасности, связанные с использованием действия -exec; вместо этого вы должны использовать опцию -execdir.

-exec команда {} +

Этот вариант действия -exec запускает указанную команду для выбранных файлов, но командная строка создается путем добавления каждого выбранного имени файла в конце; общее количество вызовов команды будет намного меньше, чем количество совпавших файлов. Командная строка строится почти так же, как xargs создает свои командные строки. Только один экземпляр `{} 'разрешен в команде. Команда выполняется в начальном каталоге.

5 голосов
/ 19 октября 2016

Я столкнулся с той же проблемой на Mac OSX , используя оболочку ZSH : в этом случае нет опции -t для mv, поэтому мне пришлось искать другуюрешение.Однако следующая команда прошла успешно:

find .* * -maxdepth 0 -not -path '.git' -not -path '.backup' -exec mv '{}' .backup \;

Секрет был в кавычках .Нет необходимости, чтобы скобки были в конце команды exec.

Я тестировал под Ubuntu 14.04 BASH и ZSH снарядов), он работает так же.

Однако при использовании знака + действительно кажется, что он должен находиться в конце команды exec.

3 голосов
/ 13 марта 2017

Стандартный эквивалент find -iname ... -exec mv -t dest {} + для find реализаций, которые не поддерживают -iname или mv реализаций, которые не поддерживают -t, состоит в использовании оболочки для изменения порядка аргументов:

find . -name '*.[cC][pP][pP]' -type f -exec sh -c '
  exec mv "$@" /dest/dir/' sh {} +

Используя -name '*.[cC][pP][pP]', мы также избегаем зависимости от текущей локали, чтобы решить, какая заглавная версия c или p.

Обратите внимание, что +, напротивзначение ; не является особенным в любой оболочке, поэтому его не нужно заключать в кавычки (хотя цитирование не повредит, за исключением, конечно, таких оболочек, как rc, которые не поддерживают \ в качестве оператора цитирования).

Конечный / в /dest/dir/ таков, что mv завершается с ошибкой вместо переименования foo.cpp в /dest/dir в случае, когда был найден только один файл cpp и /dest/dirне существует или не является каталогом (или символической ссылкой на каталог).

0 голосов
/ 10 апреля 2011

нет, разницу между + и \; следует обратить вспять. + добавляет файлы в конец команды exec, затем запускает команду exec и \; запускает команду для каждого файла.

Проблема в том, что find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ должно быть find . -type f -iname '*.cpp' -exec mv {} ./test/ +, нет необходимости избегать его или прекратить +

xargs я давно не использовал, но думаю работает как +.

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