Відповіді:
Оскільки тільки оболонка знає, як запускати функції оболонки, вам потрібно запустити оболонку для запуску функції. Вам також потрібно позначити свою функцію для експорту export -f
, інакше підзарядка не успадкує їх:
export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;
find . -exec bash -c 'dosomething "$0"' {} \;
це, ви обробляєте пробіли (та інші дивні символи) у іменах ...
export -f
Працюватиме тільки в деяких версіях Баша. Це не posix, не crossplatforn, /bin/sh
буде з ним помилка
find . | while read file; do dosomething "$file"; done
while read
на цикл for; for item in $(find . ); do some_function "${item}"; done
Відповідь Джека вище є чудовою, але має кілька підводних каменів, які легко подолати:
find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done
Для цього використовується null як роздільник, а не передача рядків, тому назви файлів із стрічковими каналами працюватимуть. Він також використовує -r
прапор, який відключає нахил зворотної косої риси, без того, щоб рисові коси в імені файлів не працювали. Він також очищається, IFS
щоб потенційні відсталі пробіли в іменах не були відкинуті.
/bin/bash
але не працюватиме /bin/sh
. Шкода.
Додайте цитати, {}
як показано нижче:
export -f dosomething
find . -exec bash -c 'dosomething "{}"' \;
Це виправляє будь-яку помилку через спеціальні символи, повернуті find
, наприклад файли з дужками в їх імені.
{}
. Це порушить назву файлу, що містить подвійні лапки. touch '"; rm -rf .; echo "I deleted all you files, haha
. На жаль
-exec bash -c 'echo $0' '{}' \;
Зауважте, що при використанні bash -c
$ 0 - це перший аргумент, а не ім'я сценарію.
Для підвищення ефективності багато людей використовують xargs
обробку результатів масою, але це дуже небезпечно. Через це був введений альтернативний метод, який вводив find
результати масово.
Зауважте, що цей метод може містити деякі застереження, наприклад, наприклад, вимога в POSIX find
- мати {}
в кінці команди.
export -f dosomething
find . -exec bash -c 'for f; do dosomething "$f"; done' _ {} +
find
передасть багато результатів як аргументів на один виклик bash
і for
-loop повторюється через ці аргументи, виконуючи функцію dosomething
на кожному з них.
Вищевказане рішення починається з аргументів $1
, через що існує _
(що представляє $0
).
Таким же чином, я вважаю, що прийняту верхню відповідь слід виправити
export -f dosomething
find . -exec bash -c 'dosomething "$1"' _ {} \;
Це не тільки більш розумно, тому що аргументи завжди слід починати $1
, але також використання $0
може призвести до несподіваної поведінки, якщо ім'я файлу, яке повертається, find
має спеціальне значення для оболонки.
Запропонуйте собі скрипт, передаючи кожен елемент, знайдений як аргумент:
#!/bin/bash
if [ ! $1 == "" ] ; then
echo "doing something with $1"
exit 0
fi
find . -exec $0 {} \;
exit 0
Коли ви запускаєте сценарій самостійно, він знаходить те, що шукаєте, і називає себе, передаючи кожен результат пошуку як аргумент. Коли сценарій запускається з аргументом, він виконує команди на аргументі, а потім виходить.
find: ‘myscript.sh’: No such file or directory
якщо почнеться як bash myscript.sh
…
Для тих, хто шукає функцію bash, яка буде виконувати задану команду для всіх файлів у поточному каталозі, я склав один із наведених відповідей:
toall(){
find . -type f | while read file; do "$1" "$file"; done
}
Зауважте, що він порушується з іменами файлів, що містять пробіли (див. Нижче).
Як приклад, візьміть цю функцію:
world(){
sed -i 's_hello_world_g' "$1"
}
Скажіть, що я хотів змінити всі екземпляри привіт світу у всіх файлах у поточному каталозі. Я б робив:
toall world
Щоб захистити будь-які символи у файлах файлів, використовуйте:
toall(){
find . -type f -print0 | while IFS= read -r -d '' file; do "$1" "$file"; done
}
(але вам потрібна find
ця ручка, -print0
наприклад, GNU find
).
Для довідки я уникаю цього сценарію, використовуючи:
for i in $(find $dir -type f -name "$name" -exec ls {} \;); do
_script_function_call $i;
done;
Отримайте результат пошуку в поточному файлі сценарію та перейдіть на вихід, як вам захочеться. Я згоден з прийнятою відповіддю, але не хочу виставляти функцію поза моїм файлом сценарію.
Таким чином виконати функцію неможливо .
Щоб подолати це, ви можете розмістити свою функцію в сценарії оболонки і викликати її з find
# dosomething.sh
dosomething () {
echo "doing something with $1"
}
dosomething $1
Тепер використовуйте його в пошуку як:
find . -exec dosomething.sh {} \;
dosomething $1
=> dosomething "$1"
і правильно find . -exec bash dosomething.sh {} \;
Для того, щоб забезпечити необхідні доповнення і уточнення до деяких інші відповіді, якщо ви використовуєте опцію насипну для exec
або execdir
( -exec command {} +
), і ви хочете , щоб отримати всі позиційні аргументи, ви повинні розглянути звернення $0
з bash -c
. Більш конкретно, розглянемо команду нижче, яка використовує, bash -c
як було запропоновано вище, і просто повторює шляхи до файлів, що закінчуються на ".wav" з кожного знайденого каталогу:
find "$1" -name '*.wav' -execdir bash -c 'echo $@' _ {} +
Посібник з bash говорить:
If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, they are assigned to the
positional parameters, starting with $0.
Тут 'check $@'
знаходиться командний рядок та _ {}
є аргументи після командного рядка. Зауважте, що $@
це спеціальний позиційний параметр у bash, який розширюється на всі позиційні параметри починаючи з 1 . Також зауважте, що за допомогою -c
параметра перший аргумент присвоюється позиційному параметру $0
. Це означає, що якщо ви спробуєте отримати доступ до всіх позиційних параметрів $@
, ви отримаєте лише параметри починаючи з $1
і вгору. Саме тому у відповіді Домініка є той _
, який є фіктивним аргументом для заповнення параметра $0
, тому всі потрібні аргументи будуть доступні пізніше, якщо ми будемо використовувати, $@
наприклад, розширення параметра або цикл for, як у цій відповіді.
Звичайно, подібно до прийнятої відповіді, bash -c 'shell_function $0 $@'
це також діятиме, чітко проходячи $0
, але знову ж таки, вам доведеться пам’ятати, що $@
не буде працювати, як очікувалося.
Не безпосередньо, ні. Знайти виконується в окремому процесі, а не в оболонці.
Створіть скрипт оболонки, який виконує ту саму роботу, що і ваша функція, і знайдіть, чи може -exec
це.
$0
.