найти -exec функцию оболочки в Linux?

Есть ли способ получить find для выполнения функции, которую я определяю в оболочке? Например:

dosomething () {
  echo "doing something with $1"
}
find . -exec dosomething {} \;

Результат:

find: dosomething: No such file or directory

Есть ли способ получить find -exec, чтобы увидеть dosomething?

Ответ 1

Поскольку только оболочка знает, как запускать функции оболочки, вам нужно запустить оболочку для запуска функции. Вы также должны пометить свою функцию для экспорта с помощью export -f, иначе подоболочка не наследует их:

export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;

Ответ 2

find . | while read file; do dosomething "$file"; done

Ответ 3

Добавьте кавычки в {}, как показано ниже:

export -f dosomething
find . -exec bash -c 'dosomething "{}"' \;

Это исправляет любую ошибку из-за специальных символов, возвращаемых find, например файлы с круглыми скобками в их имени.

Ответ 4

Ответ на Jak выше велик, но есть пара ошибок, которые легко преодолеть:

find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done

В качестве ограничителя вместо null, используется значение null, поэтому имена файлов с линией перевода будут работать. Он также использует флаг -r, который отключает экранирование обратного слэша, без его обратных косов в именах файлов не будет работать. Он также очищает IFS, так что потенциальные конечные пробелы в именах не отбрасываются.

Ответ 5

Иметь вызов script, передавая каждый найденный элемент в качестве аргумента:

#!/bin/bash

if [ ! $1 == "" ] ; then
   echo "doing something with $1"
   exit 0
fi

find . -exec $0 {} \;

exit 0

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

Ответ 6

Обработка результатов навалом

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

Ответ 7

Для тех из вас, кто ищет функцию 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).

Ответ 8

Невозможно выполнить эту функцию таким образом.

Чтобы преодолеть это, вы можете поместить свою функцию в оболочку script и вызвать ее из find

# dosomething.sh
dosomething () {
  echo "doing something with $1"
}
dosomething $1

Теперь используйте его в find как:

find . -exec dosomething.sh {} \;

Ответ 9

Поместите функцию в отдельный файл и получите find, чтобы выполнить это.

Функции оболочки являются внутренними для оболочки, в которой они определены; find никогда не сможет их увидеть.

Ответ 10

Я нахожу самый простой способ, как следует, повторяя две команды в одиночном do

func_one () {
  echo "first thing with $1"
}

func_two () {
  echo "second thing with $1"
}

find . -type f | while read file; do func_one $file; func_two $file; done

Ответ 11

Не прямо, нет. Поиск выполняется в отдельном процессе, а не в вашей оболочке.

Создайте оболочку script, которая выполняет ту же работу, что и ваша функция, и найдите -exec.

Ответ 12

Для справки, я избегаю этого сценария, используя:

for i in $(find $dir -type f -name "$name" -exec ls {} \;); do
  _script_function_call $i;
done;

Получите вывод find в текущем файле скрипта и выполните итерацию по выводу, как вам захочется. Я согласен с принятым ответом, но я не хочу показывать функцию за пределами моего файла сценария.

Ответ 13

Я бы вообще не использовал -exec. Почему бы не использовать xargs?

find . -name <script/command you're searching for> | xargs bash -c