Ну, после того, как я спросил, моя очередь «дать» :) Сообществу. Я исследовал эту функцию автоматической загрузки, которая мне нужна, и предложил 2 реализации, я привел одну из них здесь, поэтому некоторые могут предложить улучшения или указать на ошибки. Я опубликую второй на втором посте.
В двух реализациях будет выполнено несколько тестовых случаев, поэтому перед представлением реализаций я представлю общие тестовые примеры. У нас есть 2 каталога a1 / и a2 /, в которых определения функций хоста находятся в файле с тем же именем, что и у функции, каждый каталог может считаться каталогом «package», содержащим функции для этого пакета, а затем функция там находится в пространстве имен с именем пакета. (имя dir), за редким исключением для целей тестирования.
./a1/ac_f3::
function ac_f3
{ echo "In a1 ac_f3() : args=$@"
}
./a1/a1_f1::
function a1_f1
{ echo "In a1_f1() : args=$@"
}
./a1/a1_f2::
function a1_f22
{ echo "In a1_f2() : args=$@"
}
./a2/ac_f3::
function f3
{ echo "In a2 ac_f3() : args=$@"
}
./a2/a2_f1::
function a2_f1
{ echo "In a2_f1() : args=$@"
}
ac_f3 - это функция, которая не является пространством имен, а затем является общей для обоих dir a1 / a2 /, но с другой реализацией, это должно продемонстрировать приоритет $ FPATH.
a1_f2 является поддельным, он не реализует функцию a1_f2 (), и тогда мы должны изящно потерпеть неудачу.
a1_f1, a2_f1, просто реализовать a1_f1 () a2_f2 ( ), и должен быть найден и выполнен.
реализация command_not_found_handle
Спасибо Чарльзу за использование опции command_not_found_handle, потому что, безусловно, автоматически загружаемая функция связана с тем фактом, что 'команда' не найдена, и затем мы пытаемся найти автоматическую загрузку для загрузки и выполнения.
Но, что удивительно, оболочка bash имеет интересную «особенность», то есть некоторое недокументированное поведение.
Bash do c говорит.
If the search is unsuccessful, the shell searches for a defined
shell function named command_not_found_handle. If that
function exists, it is invoked with the original command and
the original command's arguments as its arguments, and the
function's exit status becomes the exit status of the shell.
If that function is not defined, the shell prints an error
message and returns an exit status of 127.
Это вводит в заблуждение, потому что здесь мы говорим о вызове функции command_not_found_handle (), а затем можем вывести «из контекста оболочки», а это не так.
В логах оболочки c нам не удалось получить псевдоним, затем не удалось получить функцию, затем не удалось получить программу «external to the shell», и оболочка уже находится в подпрограмме. режим создания оболочки, так что command_not_found_handle () вызывается, но в подоболочке. не контекст оболочки. Это может быть хорошо, но «забавная особенность» здесь в том, что созданный подпроцесс не является чистым, его $$ и $ PPID установлены неправильно, возможно, это будет исправлено однажды. Чтобы продемонстрировать эту функцию bash, мы можем сделать
function command_not_found_handle
{ echo $$ ; sh -c 'echo $PPID'
}
PW$ # In a shell context invocation
PW$ command_not_found_handle
2746
2746
PW$ # In a subshell invocation (via command not found)
PW$ qqq
2746
3090
Возвращаясь к нашей функции автозагрузки, это означает, что мы хотим установить больше функций в экземпляре оболочки, ничего, что нельзя сделать в подоболочке, поэтому в основном command_not_found_handle () имеет небольшую помощь и ничего не может поделать с сигналом о том, что его родитель был введен (тогда команда не найдена), мы будем использовать эту функцию в нашей реализации.
# autoload
# This file must be sourced
# - From your rc files if you need autoloadable fuctions from your
# interactive shell
# - From any script that need autoloadable functions.
#
# The FPATH must be set with a set of dirs/ where to look to find
# file name match the function name to source and execute.
#
# Note that if FPATH is exported, this is a way to export functions to
# script subshells
# Create a default command_not_found_handle if none exist
declare -F command_not_found_handle >/dev/null ||
function command_not_found_handle { ! echo bash: $1 command not found>&2; }
# Rename current command_not_found_handle
_cnf_body=$(declare -f command_not_found_handle | tail -n +2)
eval "function _cnf_prev $_cnf_body"
# Change USR1 to your liking
CNF_SIG=USR1
function autoload
{ declare f=$1 ; shift
declare d s
for d in $(IFS=:; echo $FPATH)
do s=$d/$f
[ -f $s -a -r $s ] &&
{ . $s
declare -F $f >/dev/null ||
{ echo "$s exist but don't define $f" >&2 ; return 127
}
$f "$@" ; return
}
done
_cnf_prev $f "$@"
}
trap 'autoload ${BASH_COMMAND[@]}' $CNF_SIG
function command_not_found_handle
{ kill -$CNF_SIG $$
}
ПРЕДУПРЕЖДЕНИЕ, если вы когда-либо используете этот файл автозагрузки подготовлен для исправления bash, он может однажды отразить реальный $$ $ PPID, и в этом случае вам нужно будет исправить приведенный выше фрагмент с $ PPID вместо $$ .
Результаты.
PW$ . /path/to/autoload
PW$ FPATH=a1:a2
PW$ a1_f1 11a 11b 11c
In a1_f1() : args=11a 11b 11c
PW$ a2_f1 21a 21b 21c
In a2_f1() : args=21a 21b 21c
PW$ a1_f2 12a 12b 12c
a1/a1_f2 exist but don't define a1_f2
PW$ ac_f3 c3a c3b c3c
In a1 ac_f3() : args=c3a c3b c3c
PW$ qqq
Command 'qqq' not found, did you mean:
command 'qrq' from snap qrq (0.3.1)
command 'qrq' from deb qrq
See 'snap info <snapname>' for additional versions.
То, что мы получили здесь, правильно, a1_f1 () a2_f1 () найдены, загружены, выполнены.
a1_f2 () нигде не найти, несмотря на наличие файла, в котором он может быть размещен.
В вызове qqq отображаются цепочки обработчиков, идет функция автозагрузки fist, затем пакет ubuntu command-not-found (если установлен) ) значит мы не теряйте пользовательский интерфейс command_not_found_handle ().
Обратите внимание, что здесь нет функций 'admin', таких как добавление / удаление / перезагрузка функций.
Добавление - это вопрос установки файла в каталогах, присутствующих в $ FPATH
Удаление - это удаление исходного файла и отключение -f функции
Перезагрузка - это вопрос редактирования исходного файла и отмены -f функции.
Функция перезагрузки может быть довольно удобной во время разработки в интерактивной оболочке, но все это можно сделать с помощью простого unset -f funcname
, так что в основном вы редактируете свой исходный файл , сбросьте функцию, затем вызовите ее, вы получите последнюю версию. То же самое может произойти в демоне сценария, можно реализовать сигнал для демона, и обработчик ловушек просто сбросит набор функций, которые затем будут перезагружены без остановки / перезапуска демона.
Еще одна особенность заключается в том, что возможна оболочка «пакет», то есть исходный файл может реализовывать «много» функций, некоторые являются внешним API, другие являются внутренними по отношению к пакету, поскольку в оболочке все плоско, функции располагаются в пространстве имен, а затем каждый из внешних функций API ( хотя и задокументировано) может быть жестко связано с тем же файлом. Первый использованный внешний API загрузит все функции пакета.
В моем проекте документация извлекается из источников пакетов, а затем выводятся жесткие ссылки и выполняется сборка.
PRO и CON
PRO Здесь мы получили легкую подпись в источнике автозагрузки, т.е. из сценариев или из bash r c файла (интерактивного), определения из автозагрузки () является скромным.
Это очень динамично c, в том смысле, что загрузка и выполнение функции действительно откладывается до тех пор, пока она действительно не понадобится.
CONs Он захватывает номер сигнала, который не был бы необходим, если бы command_not_found_handle () была реальной функцией, вызываемой из контекста оболочки, это может произойти однажды.
Он реализован на bash функции, которая может двигаться (неправильно, $$ $ PPID), а затем нуждается в обслуживании на движущейся цели.
Заключение Эта реализация для меня в порядке (я Пофиг потерять SIGUSR1). Идеальным решением было бы, чтобы command_not_found_handle () была бы аккуратно реализована и затем вызывалась в контексте оболочки. Подобная реализация была бы возможна без какого-либо сигнала.