Использование точки с запятой (;) vs plus (+) с exec в find

Почему разница между использованием

find . -exec ls '{}' \+

и

find . -exec ls '{}' \;

Я получил:

$ find . -exec ls  \{\} \+
./file1  ./file2

.:
file1  file2  testdir1

./testdir1:
testdir2

./testdir1/testdir2:


$ find . -exec ls  \{\} \;
file1  file2  testdir1
testdir2
./file2
./file1

Ответ 1

Это лучше всего проиллюстрировать на примере. Скажем, что find отображает эти файлы:

file1
file2
file3

Используя -exec с точкой с запятой (find . -exec ls '{}' \;), выполните

ls file1
ls file2
ls file3

Но если вместо этого использовать знак плюса (find . -exec ls '{}' \+), то как можно больше имен файлов передается в качестве аргументов для одной команды:

ls file1 file2 file3

Количество имен файлов ограничено максимальной длиной командной строки системы. Если команда превышает эту длину, команда будет вызываться несколько раз.

Ответ 2

Все ответы до сих пор верны. Я предлагаю это как более ясную (для меня) демонстрацию поведения, которое описывается с помощью echo, а не ls:

С точкой с запятой команда echo вызывается один раз для каждого файла (или другого объекта файловой системы):

$ find . -name 'test*' -exec echo {} \;
./test.c
./test.cpp
./test.new
./test.php
./test.py
./test.sh

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

$ find . -name 'test*' -exec echo {} \+
./test.c ./test.cpp ./test.new ./test.php ./test.py ./test.sh

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

Ответ 3

от человека

-exec команда;

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

-exec command {} +

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

так, как я его понимаю; \; выполняет отдельные команды и + добавляет каждое имя. его в основном способ, которым он выполняется, поскольку\является побегом, поэтому его

ls testdir1; ls testdir2 

против

ls testdir1 testdir2

Выполнение вышеуказанного в моей оболочке отразило вывод вашего вопроса.

ОБНОВЛЕНИЕ 2

Итак, зачем вы хотите использовать +

скажем, у меня есть два файла: 1.tmp и 2.tmp

1.tmp:

1
2
3

2.tmp:

0
2
3

работает

 find *.tmp -exec diff {} \;
> diff: missing operand after `1.tmp'
> diff: Try `diff --help' for more information.
> diff: missing operand after `2.tmp'
> diff: Try `diff --help' for more information.

если вы используете + и объединяете результаты поиска так:

find *.tmp -exec diff {} \+
1c1,3
< 1
---
> 0
> 2
> 30

поэтому в этом случае его разность между diff 1.tmp; diff 2.tmp и diff 1.tmp 2.tmp

Есть случаи, когда \; подходит и + будет необходимо. использование + с rm является одним из таких экземпляров, где, если вы удаляете большое количество файлов, скорость которых значительно улучшилась; Мне всегда нравится больше узнать о поиске, это такой мощный и удобный инструмент, я надеюсь, что этого достаточно, чтобы объяснить различия.

Ответ 4

Здесь сделка: find имеет специальный синтаксис. Вы используете {} так, как они есть, потому что они имеют смысл находить в качестве пути к найденному файлу, и (большинство) оболочек не интерпретируют их иначе. Вам нужна обратная косая черта \;, потому что точка с запятой имеет смысл для оболочки, которая ест ее, прежде чем find сможет ее получить. Итак, какая находка хочет видеть ПОСЛЕ оболочки, в списке аргументов, переданных программе C, есть

"- exec", "rm", "{}", ";"

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

Вы можете уйти с помощью \{\}, потому что интерпретация текста \{\} с оболочкой называется просто {}. Аналогично, вы можете использовать '{}'.

То, что вы не можете сделать, это использовать

 -exec 'rm {} ;'

потому что оболочка интерпретирует это как один аргумент,

"- exec", "rm {};"

и "rm {};" это не имя команды. (По крайней мере, если кто-то действительно не притворяется.)

Обновление

разница между

$ ls file1
$ ls file2

и

$ ls file1 file2

Символ + связывает имена в командной строке.

Ответ 5

Разница между ; (точкой с запятой) или + (плюс знак) заключается в том, как аргументы передаются в параметр find -exec/-execdir. Например:

  • с помощью ; будет выполняться несколько команд (отдельно для каждого аргумента),

    Пример:

    $ find /etc/rc* -exec echo Arg: {} ';'
    Arg: /etc/rc.common
    Arg: /etc/rc.common~previous
    Arg: /etc/rc.local
    Arg: /etc/rc.netboot
    

    Все следующие аргументы find считаются аргументами команды.

    Строка {} заменяется текущим именем файла, который обрабатывается.

  • с помощью + будут выполняться наименьшие возможные команды (по мере объединения аргументов). Это очень похоже на то, как работает команда xargs, поэтому она будет использовать как можно больше аргументов для каждой команды, чтобы избежать превышения максимального предела аргументов на строку.

    Пример:

    $ find /etc/rc* -exec echo Arg: {} '+'
    Arg: /etc/rc.common /etc/rc.common~previous /etc/rc.local /etc/rc.netboot
    

    Командная строка создается путем добавления каждого имени выбранного файла в конце.

    Внутри команды допускается только один экземпляр {}.

См. также:

Ответ 6

мы пытались найти файл для домашнего хозяйства.

найти. -exec echo {} \; команда побежала за ночь, в итоге не получилось.

найти. -exec echo {}\+ имеет результаты и занимает всего несколько часов.

Надеюсь, что это поможет.