Як я можу використовувати дві команди bash в команді -exec find?


32

Чи можливо використовувати 2 команди в -execчастині findкоманди?

Я спробував щось на кшталт:

find . -name "*" -exec  chgrp -v new_group {}  ; chmod -v 770 {}  \;

і я отримую:

знайти: відсутній аргумент до -exec
chmod: не може отримати доступ {}: немає такого файлу чи каталогу
chmod: не може отримати доступ ;: такого файлу чи каталогу немає

Відповіді:


44

Щодо findкоманди, ви також можете просто додати більше -execкоманд підряд:

find . -name "*" -exec chgrp -v new_group '{}' \; -exec chmod -v 770 '{}' \;

Зауважте, що ця команда за своїм результатом еквівалентна використанню

chgrp -v new_group file && chmod -v 770 файл

на кожен файл.

Всі findпараметри «s , такі як -name, -exec, -sizeі так далі, насправді є тести : findбуде продовжувати працювати їх один за іншим, поки вся ланцюг досі оцінюється в вірно . Таким чином, кожна послідовна -execкоманда виконується лише в тому випадку, якщо попередні повернули справжнє значення (тобто 0статус виходу команд). Але findтакож розуміє логічні оператори, такі як або ( -o), а не ( !). Тому, щоб використовувати ланцюжок -execтестів незалежно від попередніх результатів, потрібно використовувати щось подібне:

find . -name "*" \( -exec chgrp -v new_group {} \; -o -exec chmod -v 770 {} \; \)

4
+1: Так, це найелегантніший спосіб зробити це. Якщо ви можете пояснити, чому ви використовуєте '{}'(апострофи навколо брекетів), відвідайте: unix.stackexchange.com/q/8647/4485
користувач невідомий

1
@user На жаль, я не знаю, чи все-таки це потрібно. Я зробив тест лише зараз і не натрапив на ситуацію, коли це щось змінило б. Я здогадуюсь, що вимерла просто "добра практика".
rozcietrzewiacz

2
Лапки важливі для файлів з пробілами в їх назвах.
naught101

17
find . -name "*" -exec sh -c 'chgrp -v new_group "$0" ; chmod -v 770 "$0"' {} \;

@Gilles: Дивовижне -cдивне поводження в $ 0 змушує мене думати, що це неправильно кожного разу, коли я дивлюся на це, але це, безумовно, правильно.
дероберт

Мені подобається, що явна оболонка визначена ...
djangofan

Ця відповідь (і відповідь Джайлса) здається кращою відповіддю на поставлене запитання sh -c.

14

Ваша команда спочатку розбирається оболонкою на дві команди, розділені знаком a ;, що еквівалентно новому рядку:

find . -name "*" -exec chgrp -v new_group {}
chmod -v 770 {} \;

Якщо ви хочете запустити команду оболонки, явно викликайте оболонку з bash -c(або sh -cякщо вам не байдуже, що оболонка конкретно баш):

find . -name "*" -exec sh -c 'chgrp -v new_group "$0"; chmod -v 770 "$0"' {} \;

Зверніть увагу на використання {}в якості аргументу оболонки; це нульовий аргумент (як правило, це назва оболонки або скрипту, але це не має значення), звідси посилається як "$0".

Ви можете передавати кілька імен файлів оболонці одночасно і змушувати оболонку повторювати через них, це буде швидше. Тут я передаю _як ім'я сценарію, і наступні аргументи - це назви файлів, які for x(ярлик для for x in "$@") повторюється.

find . -name "*" -exec sh -c 'for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done' _ {} +

Зауважте, що оскільки bash 4 або zsh, вам тут взагалі не потрібно. У bash, запустіть shopt -s globstar(помістіть його у свій ~/.bashrc), щоб активувати **/стоячи для рекурсивного глобального каталогу. (У zsh, це активно весь час.) Потім

chgrp -v new_group -- **/*; chmod -v 770 -- **/*

або якщо ви хочете, щоб файли були повторені в порядку

for x in **/*; do
  chgrp -v new_group -- "$x"
  chmod -v 770 -- "$x"
done

Однією з різниць findкоманди є те, що оболонка ігнорує крапкові файли (файли, назва яких починається з а .). Щоб включити їх у bash, перший набір GLOBIGNORE=.:..; в zsh, використовувати **/*(D)як глобус.


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