Использование точки с запятой (;) против плюс (+) с exec в find - PullRequest
129 голосов
/ 22 мая 2011

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

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

Ответы [ 6 ]

207 голосов
/ 22 мая 2011

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

file1
file2
file3

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

ls file1
ls file2
ls file3

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

ls file1 file2 file3

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

33 голосов
/ 22 мая 2011

Все ответы пока верны. Я предлагаю это как более ясную (для меня) демонстрацию поведения, которое описано с использованием 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 выдает большое количество результатов, вы можете обнаружить, что вызываемая команда ограничивает количество аргументов.

15 голосов
/ 22 мая 2011

от мужчины

-exec команда;

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

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

Этот вариант опции -exec запускает указанную команду на выбранные файлы, но командная строка строится путем добавления каждое выбранное имя файла в конце; общее количество инвока- количество команд будет намного меньше числа совпавшие файлы. Командная строка построена во многом таким же образом что 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 является одним из таких случаев, когда при удалении большого количества файлов скорость значительно улучшается; Мне всегда нравится больше узнавать о find, это такая мощная и удобная утилита, я надеюсь, что этого достаточно для объяснения различий.

9 голосов
/ 22 мая 2011

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

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

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

Вы можете избежать неприятностей с \{\}, потому что интерпретация \{\} в кавычках - это просто {}. Точно так же вы можете использовать '{}'.

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

 -exec 'rm {} ;'

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

"- exec", "rm {};"

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

Обновление

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

$ ls file1
$ ls file2

и

$ ls file1 file2

+ объединяет имена в командной строке.

1 голос
/ 01 августа 2017

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

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

    Пример:

    $ 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
    

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

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

См. также:

0 голосов
/ 07 июня 2016

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

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

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

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

...