найти -exec функцию оболочки в Linux? - PullRequest
163 голосов
/ 01 декабря 2010

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

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

Результат этого:

find: dosomething: No such file or directory

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

Ответы [ 13 ]

229 голосов
/ 01 декабря 2010

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

export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;
98 голосов
/ 13 декабря 2011
find . | while read file; do dosomething "$file"; done
18 голосов
/ 16 декабря 2011

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

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

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

17 голосов
/ 14 октября 2014

Ответ Джака выше, но у него есть несколько ловушек, которые легко преодолеть:

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

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

8 голосов
/ 22 августа 2014

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

#!/bin/bash

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

find . -exec $0 {} \;

exit 0

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

7 голосов
/ 08 ноября 2016

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

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

3 голосов
/ 09 апреля 2017

Для тех из вас, кто ищет функцию bash, которая будет выполнять данную команду для всех файлов в текущем каталоге, я скомпилировал один из приведенных выше ответов:

toall(){
    find . -type f | while read file; do "$1" "$file"; done
}

Обратите внимание, что он ломаетсяс именами файлов, содержащими пробелы (см. ниже).

В качестве примера возьмем эту функцию:

world(){
    sed -i 's_hello_world_g' "$1"
}

Скажем, я хотел изменить все экземпляры hello to world во всех файлахв текущем каталоге.Я бы сделал:

toall world

Чтобы быть в безопасности с любыми символами в именах файлов, используйте:

toall(){
    find . -type f -print0 | while IFS= read -r -d '' file; do "$1" "$file"; done
}

(но вам нужен find, который обрабатывает -print0, например, GNU find).

1 голос
/ 20 января 2019

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

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

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

1 голос
/ 07 июля 2017

Я считаю, что проще всего следовать, повторяя две команды в одном до

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
1 голос
/ 01 декабря 2010

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

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

...