2010-04-13 3 views
7

У меня есть сценарий Bourne Shell, который имеет несколько функций в нем, и позволяет назвать следующим образом:получить список имен функций в сценарии оболочки

my.sh <func_name> <param1> <param2>

Внутри FUNC_NAME() будет вызывать с param1 и param2.

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

Вопрос: как мне получить список всех имен функций в скрипте изнутри скрипта?

Хотелось бы избежать анализа и поиска шаблонов функций. Слишком легко ошибаться.

Спасибо, Alex

обновление: код. Требуется, чтобы моя функция help() была похожа на main() - функция, добавленная в код, автоматически добавляется в справку.

#!/bin/sh 

# must work with "set -e" 

foo() 
{ 
    echo foo: -$1-$2-$3- 
    return 0 
} 

# only runs if there are parameters 
# exits 
main() 
{ 
    local cmd="$1" 
    shift 
    local rc=0 
    $cmd "[email protected]" || rc=$? 
    exit $rc 
} 

if [[ "$*" ]] 
then 
    main "[email protected]" 
    die "how did we get here?" 
fi 
+1

"Bourne оболочки"? Я не знаю о ** любом ** дистрибутиве Linux, который отправляет Bourne из коробки или когда-либо; '/ bin/sh' почти универсально POSIX sh (более десятилетний стандарт с ненулевым набором несовместимостей, например, Bourne рассматривает'^'как символ канала, POSIX sh не делает, Bourne использует' $ [] ' для математики POSIX sh использует '$ (()) и т. д.). –

+0

@CharlesDuffy У вас есть источник для этого? –

+0

@OleTange, какая часть? (Я, конечно, полагался на «на Linux», чтобы исключить такие случаи, как SunOS/более старая Solaris, где POSIX sh находится в другом месте, но (1), на которые ссылались в моем комментарии, и (2) вопрос так отмеченном). –

ответ

9

Вы можете получить список функций в своем скрипте, используя команду grep для вашего собственного скрипта. Чтобы этот подход работал, вам нужно будет структурировать свои функции определенным образом, чтобы grep мог их найти. Вот пример:

$ cat my.sh 
#!/bin/sh 

function func1() # Short description 
{ 
    echo func1 parameters: $1 $2 
} 

function func2() # Short description 
{ 
    echo func2 parameters: $1 $2 
} 

function help() # Show a list of functions 
{ 
    grep "^function" $0 
} 

if [ "_$1" = "_" ]; then 
    help 
else 
    "[email protected]" 
fi 

Вот интерактивная демонстрация:

$ my.sh 
function func1() # Short description 
function func2() # Short description 
function help() # Show a list of functions 


$ my.sh help 
function func1() # Short description 
function func2() # Short description 
function help() # Show a list of functions 


$ my.sh func1 a b 
func1 parameters: a b 

$ my.sh func2 x y 
func2 parameters: x y 

Если у вас есть «частная» функция, которую вы не хотите, чтобы показать в помощи, а затем опустить функцию» "часть:

my_private_function() 
{ 
    # Do something 
} 
+0

способ doxygen :) Это хорошо, поскольку он позволяет печатать описание, а не просто имя функции. Но никакое принуждение, забытый комментарий не является забытой функцией. Спасибо –

+0

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

+1

, если вам интересно, ваше решение с eval messes пробелов в параметрах, то есть my.sh func1 «1 1» 2 3 будет call func1 с $ 1 = 1 $ 2 = 1 $ 3 = 2 $ 4 = 3 вместо $ 1 = "1 1" и т. д. Избегайте помощи eval –

1

Самое лучшее, что нужно сделать, это сделать массив (вы используете Баш), который содержит функции, которые вы хотите рекламировать и есть ваша функция помощи перебрать и распечатать их.

Вызов только set будет выполнять функции, но полностью. Вам все равно придется разбирать то, что ищет вещи, заканчивающиеся на(), чтобы получить пресловутые символы .

Его также, вероятно, целесообразнее использовать что-то вроде getopt, чтобы превратить --function-name в function_name с аргументами. Но, ну, нормальный, относительный, и вы не разместили код :)

Другой вариант - создать loadable for bash (вилка set), которая выполняет это. Честно говоря, я бы предпочел использовать синтаксический анализ, прежде чем писать загружаемую для этой задачи.

+0

@Tim +1 за ваше предложение. @ n-alexander Я думаю, что нет возможности получить метаданные о функциях. Вы можете разобрать, но вы не хотите этого делать. –

+0

Вы имеете в виду использование одного и того же массива для вызова функций и их печати?Это то, что я сделал бы в C. В оболочке я надеялся, что смогу просто добавить функцию и не менять код. Но спасибо –

+0

@ n-alexander - Запрет писать собственный собственный bash для экспорта только «символов», вам нужно будет сделать две изменения для каждой функции. Я знаю, что похоже, что вы не можете «просто получить» функции, так как bash знает о них, но для этого нет никакого интерфейса. Вы на самом деле заставляете меня думать о том, чтобы сделать загружаемое для этого. –

2

Вы вызываете эту функцию без каких-либо аргументов и выплевывает „пробел“список разделенных имена функций.


function script.functions() { 
    local fncs=`declare -F -p | cut -d " " -f 3`; # Get function list 
    echo $fncs; # not quoted here to create shell "argument list" of funcs. 
} 

Чтобы загрузить функции в массив:


declare MyVar=($(script.functions)); 

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

сделать список только для чтения и доступны для экспорта в другие сценарии называют этим скриптом:


declare -rx MyVar=($(script.functions)); 

Чтобы напечатать весь список в качестве новой строки разделены:


printf "%s\n" "${MyVar[@]}"; 
+0

'declare -F' работает только (как предполагалось) в' bash', но не в 'ksh' (breaks), а не в' zsh' (где '-F' объявляет переменную с плавающей запятой). – mklement0

+0

Я подозреваю, что следующее будет немного более портативным и даст тот же результат: 'declare -f | grep '^. * \ s()' | cut -f 1 -d '' '. – destenson

10

typeset -f возвращает функции с их телами, так что простой AWK скрипт используется для срывать имена функций

f1() { :; } 
f2() { :; } 
f3() { :; } 
f4() { :; } 
help() { 
    echo "functions available:" 
    typeset -f | awk '/ \(\) $/ && !/^main/{print $1}' 
} 
main() { help; } 
main 

Этот сценарий выводит:

functions available: 
f1 
f2 
f3 
f4 
help 
+3

+1 для чистого решения, которое _potentially_ работает в 'bash',' ksh', 'zsh': поскольку вывод из' typeset -f' немного отличается от оболочек, команда 'awk' должна быть более гибкой:' typeset -f | awk '!/^ main [(]/&&/^ [^ {}] + * \ (\)/{gsub (/ [()] /, "", $ 1); print $ 1}' '. Небольшая оговорка в 'bash': если в вашей среде есть _exported_ функции,' typeset -f' также перечислит их. – mklement0

Смежные вопросы