Список определенных функций в Bash

Я пытаюсь написать код в bash, который использует интроспекцию для выбора соответствующей функции для вызова.

Определение кандидатов требует знания того, какие функции определены. Легко перечислить определенные переменные в bash, используя только расширение параметра:

$ prefix_foo="one"
$ prefix_bar="two"
$ echo "${!prefix_*}"
prefix_bar prefix_foo

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

Есть ли правильный путь?

Ответ 1

Как насчет compgen:

compgen -A function   # compgen is a shell builtin

Ответ 2

$ declare -F
declare -f ::
declare -f _get_longopts
declare -f _longopts_func
declare -f _onexit
...

Итак, Jed Daniel alias,

declare -F | cut -d" " -f3

разрезает пробел и эхо 3-го поля:

$ declare -F | cut -d" " -f3
::
_get_longopts
_longopts_func
_onexit

Ответ 3

У меня есть запись в моей .bashrc, которая гласит:

alias list='declare -F |cut -d" " -f3'

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

Удачи,

- Джед

Ответ 4

У этого нет проблем с IFS или слиянием:

readarray -t funcs < <(declare -F)

printf '%s\n' "${funcs[@]##* }"

Конечно, для этого требуется bash 4.0.

Для bash с момента использования 2.04 (немного сложнее, но эквивалентно):

IFS=$'\n' read -d '' -a funcs < <(declare -F)

Если вам нужно, чтобы код выхода этой опции был равен нулю, используйте это:

IFS=$'\n' read -d '' -a funcs < <( declare -F && printf '\0' )

Он выйдет из неуспешного (не 0), если сбой declare или read. (Благодаря @CharlesDuffy)

Ответ 5

Используйте встроенное объявление declare для отображения текущих функций:

declare -F

Ответ 6

Pure Bash:

saveIFS="$IFS"
IFS=$'\n'
funcs=($(declare -F))      # create an array
IFS="$saveIFS"
funcs=(${funcs[@]##* })    # keep only what after the last space

Затем запустите в приглашении Bash в качестве примера, отображающего функции bash -completion:

$ for i in ${funcs[@]}; do echo "$i"; done
__ack_filedir
__gvfs_multiple_uris
_a2dismod
. . .
$ echo ${funcs[42]}
_command

Ответ 7

Один (уродливый) подход заключается в grep через выход из набора:

set \
  | egrep '^[^[:space:]]+ [(][)][[:space:]]*$' \
  | sed -r -e 's/ [(][)][[:space:]]*$//'

Приветствуются лучшие подходы.

Ответ 9

Это собирает список имен функций, соответствующих любому из списка шаблонов:

functions=$(for c in $patterns; do compgen -A function | grep "^$c\$")

Grep ограничивает вывод только точными совпадениями для шаблонов.

Проверьте bash команду type как лучшую альтернативу следующему. Спасибо Чарльзу Даффи за подсказку.

Следующие ответы используются для ответа на вопрос заголовка для людей, а не для сценариев оболочки: он добавляет список имен функций, соответствующих заданным шаблонам, в обычный which список сценариев оболочки, чтобы ответить: "Какой код запускается, когда Я набираю команду?"

which() {
  for c in "[email protected]"; do
    compgen -A function |grep "^$c\$" | while read line; do
      echo "shell function $line" 1>&2
     done
    /usr/bin/which "$c"
   done
 }

Итак,

(xkcd)Sandy$ which deactivate
shell function deactivate
(xkcd)Sandy$ which ls
/bin/ls
(xkcd)Sandy$ which .\*run_hook
shell function virtualenvwrapper_run_hook

Это, возможно, является нарушением философии Unix "делайте одну вещь", но я не раз отчаялся, потому что which не нашел команду, которую должен был содержать какой-то пакет, я забыл о функциях оболочки, поэтому я поместил это в свой .profile.

Ответ 10

#!/bin/bash
# list-defined-functions.sh
# Lists functions defined in this script.
# 
# Using `compgen -A function`,
# We can save the list of functions defined before running out script,
# the compare that to a new list at the end,
# resulting in the list of newly added functions.
# 
# Usage:
#   bash list-defined-functions.sh      # Run in new shell with no predefined functions
#   list-defined-functions.sh           # Run in current shell with plenty of predefined functions
#

# Example predefined function
foo() { echo 'y'; }

# Retain original function list
# If this script is run a second time, keep the list from last time
[[ $original_function_list ]] || original_function_list=$(compgen -A function)

# Create some new functions...
myfunc() { echo "myfunc is the best func"; }
function another_func() { echo "another_func is better"; }
function superfunction { echo "hey another way to define functions"; }
# ...

# function goo() { echo ok; }

[[ $new_function_list ]] || new_function_list=$(comm -13 \
    <(echo $original_function_list) \
    <(compgen -A function))

echo "Original functions were:"
echo "$original_function_list"
echo 
echo "New Functions defined in this script:"
echo "$new_function_list"