Використання крапки з комою (;) проти плюс (+) з exec in find


159

Чому існує різниця у виході між використанням

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

Відповіді:


249

Це може бути найкраще проілюстровано на прикладі. Скажімо, що findз'являються ці файли:

file1
file2
file3

Використовуючи -execкрапку з комою ( find . -exec ls '{}' \;), буде виконано

ls file1
ls file2
ls file3

Але якщо ви використовуєте знак плюс замість ( find . -exec ls '{}' \+), якомога більше імен файлів передаються як аргументи до однієї команди:

ls file1 file2 file3

Кількість імен файлів обмежується лише максимальною довжиною командного рядка системи. Якщо команда перевищує цю довжину, команда буде викликатися кілька разів.


1
Дякую. це дуже корисно для того, щоб бажати сортувати отримані файли: знайти -maxdepth 1 -тип f -mtime -1 -exec ls -ltr {} \ +
fbas

1
Тупий q: Я зауважую, що +асоційоване з ним -execзавжди уникає, але +асоційоване з цим -mtimeне є. Ви знаєте причину? Я здогадуюсь, це звичка втекти, ;пов'язане з -exec.
кевінарпе

3
@kevinarpe Дійсно, я хотів би змінити це за звичку ;. Не уявляю, що колись потрібно втекти+
Мартін

36

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


1
Якщо ви не можете додати результати лише до числа, яке безпечно передає їх до оболонки? Принаймні, що xargsробити ... в принципі він ніколи не задихається надто багато аргументів.
Рмано

1
@Rmano: Я бачив findxargs) на Solaris випромінює більше аргументів, ніж можна було б споживати. Схоже, що xargsfind) у кінцевих обчислювачах GNU поводяться більш спритно, але не всі використовують GNU.
Johnsyweb

2
@Johnsyweb, всі POSIX findнамагаються уникати межі кількості аргументів. І це включає "Соляріс" (як мінімум 10). Де це може провалитись, якщо ви робите щось подібне find ... -exec ksh -c 'cmd "$@" "$@"' sh {} +або find ... -exec ksh -c 'files="$*" cmd "$@"' sh {} +, але findнасправді не можете звинувачувати в цьому. Зауважте, що GNU findбула однією з останніх findреалізацій для підтримки +(раніше була болем для порту сценарію до систем GNU).
Стефан Шазелас

19

Від man find:

-exec команда;

Виконати команду; вірно, якщо статус 0 повернуто. Усі наступні аргументи для пошуку вважаються аргументами команди, поки аргумент не складається з ';' зустрічається. Рядок '{}' замінюється поточним ім'ям файлу, яке обробляється скрізь, де воно трапляється в аргументах команди, а не тільки в аргументах, де він один, як у деяких версіях знаходження. Обидві ці конструкції, можливо, знадобиться уникнути (з позначкою '\') або цитувати їх, щоб захистити їх від розширення оболонкою. Див. Розділ ПРИКЛАДИ для прикладів використання параметра '-exec'. Зазначена команда виконується один раз для кожного відповідного файлу. Команда виконується в початковому каталозі. Існують неминучі проблеми із безпекою щодо використання опції -exec;

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

Цей варіант параметра -exec виконує вказану команду для вибраних файлів, але командний рядок будується додаванням кожного вибраного імені файлу в кінці ; загальна кількість викликів команди буде значно меншою, ніж кількість відповідних файлів. Командний рядок побудований приблизно так само, як xargs будує свої командні рядки. У команді дозволений лише один екземпляр "{}". Команда виконується в початковому каталозі.

Отже, як я це розумію, \;виконує окрему команду для кожного знайденого файлу find, тоді як \+додає файли та виконує одну команду над усіма ними. Характер \втечі, так що:

ls testdir1; ls testdir2 

проти

ls testdir1 testdir2

Виконання сказаного в моїй оболонці відображає результат у вашому запитанні.

приклад, коли ви хочете використовувати \+

Припустимо, два файли 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):

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

Так що в цьому випадку різниця між diff 1.tmp; diff 2.tmpіdiff 1.tmp 2.tmp

Бувають випадки, коли \;це доречно і \+буде необхідно. Використання \+з rmодним із таких випадків, коли, якщо ви видаляєте велику кількість файлів, продуктивність (швидкість) буде кращою \;.


Я також можу прочитати сторінку чоловіка. І я це зробив, але я не думаю, що я розумію різницю між використанням; vs +
Анкур Агарвал

я не думаю, що -1 було справедливим, я пояснив своє розуміння людини. Я не просто скопіював чоловіка та пішов. але я відредагував свою відповідь, щоб включити кращий приклад.
матч

10

findмає особливий синтаксис. Ви використовуєте такі {}, які вони є, оскільки вони мають значення знайти як ім'я знайденого файлу і (більшість) оболонок не інтерпретують їх інакше. Зворотна косою рисою вам потрібна, \;оскільки крапка з комою має значення для оболонки, яка з'їдає її раніше, ніж findзможе отримати її. Отже, те, що findхочеться побачити ПІСЛЯ оболонки, зроблено у списку аргументів, переданому програмі C

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

але вам потрібно \;в командному рядку отримати крапку з комою через оболонку до аргументів.

Ви можете піти звідси, \{\}оскільки тлумачення оболонки \{\}справедливо {}. Аналогічно, ви можете використовувати "{}".

Що ви не можете зробити, це використовувати

 -exec 'rm {} ;'

тому що оболонка інтерпретує це як один аргумент,

"-exec", "rm {};"

і rm {} ;не назва команди. (Принаймні, якщо хтось насправді не обернеться.)

Оновлення

різниця між ними

$ ls file1
$ ls file2

і

$ ls file1 file2

Це +вказує назви в командному рядку.


1
Я розумію, що ти кажеш. Я запитую, в чому різниця між використанням; vs +
Анкур Агарвал

1
вибачте, але ви уважно прочитали моє запитання чи мій коментар? Можливо, мені потрібно перефразовувати це. Чому існує інше o / p, коли я використовую крапку з крапкою з exec in find проти, коли я використовую плюс з exec у пошуку?
Анкур Агарвал

2
Це відмінне пояснення ЧОМУ команда така, що прийнята відповідь не охоплює. Дякую!
Шервін Ю

1

Різниця між ;(крапка з комою) або +(плюс знак) полягає в тому, як аргументи передаються в пошук -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
    

    Командний рядок будується додаванням кожного вибраного імені файлу в кінці.

    Лише один екземпляр {}дозволений в межах команди.

Дивитися також:


-5

ми намагалися знайти файл для ведення господарства.

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

знайти. -exec echo {} \ + мають результати і зайняли лише кілька годин.

Сподіваюся, це допомагає.


2
Ця відповідь не пояснює, як ці два способи працюють і як результати, отримані ними, відрізняються.
misko321
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.