Как я могу запустить функцию из скрипта в командной строке?


119

У меня есть сценарий с некоторыми функциями.

Могу ли я запустить одну из функций прямо из командной строки?

Что-то вроде этого?

myScript.sh func()

Ответы:


66

Если сценарий только определяет функции и больше ничего не делает, вы можете сначала выполнить сценарий в контексте текущей оболочки с помощью команды sourceили, .а затем просто вызвать функцию. См. help sourceДополнительную информацию.


1
Единственная проблема с этим методом заключается в том, что если вы используете его exitв своей функции, он закроет терминал после выполнения функции. Есть ли способ обойти это? @SvenMarnach
user1527227 02

@ user1527227: В этом случае перейдите к следующему ответу, если у вас есть контроль над сценарием оболочки. Если вы этого не сделаете, вы можете сначала вызвать интерактивную подоболочку (просто введите bash) и exitзавершите только подоболочку, но не ваш терминал.
Sven Marnach 03

238

Что ж, в то время как другие ответы верны - вы, безусловно, можете сделать что-то еще: если у вас есть доступ к сценарию bash, вы можете его изменить и просто поместить в конце специальный параметр, "$@"который будет расширяться до аргументов командной строки вы указываете, и, поскольку он "один", оболочка попытается вызвать их дословно; и здесь вы можете указать имя функции в качестве первого аргумента. Пример:

$ cat test.sh
testA() {
  echo "TEST A $1";
}

testB() {
  echo "TEST B $2";
}

"$@"


$ bash test.sh
$ bash test.sh testA
TEST A 
$ bash test.sh testA arg1 arg2
TEST A arg1
$ bash test.sh testB arg1 arg2
TEST B arg2

Для полировки вы можете сначала убедиться, что команда существует и является функцией:

# Check if the function exists (bash specific)
if declare -f "$1" > /dev/null
then
  # call arguments verbatim
  "$@"
else
  # Show a helpful error
  echo "'$1' is not a known function name" >&2
  exit 1
fi

16
Используйте "$@"в большинстве случаев. $@в некоторых случаях небезопасно.
fumiyas

1
Как запустить больше, чем просто функцию? например я могу бежать bash test.sh testA testB?
Джефф Панг

Это также нужно обернуть, [ ! -z "$1" ]иначе источник вызовет оператор else в некоторых версиях bash
JackLeo

Я долго искал эту волшебную переменную "$ @", чтобы использовать любую функцию, вызываемую в файле, спасибо @sdaau!
Джастин Хаммонд,

36

Следующая команда сначала регистрирует функцию в контексте, а затем вызывает ее:

. ./myScript.sh && function_name

1
Вы также можете просто использовать источник. Как в - исходный myScript.sh &&
имя_функции

17

Короче нет.

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

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


1
Я думаю, что этому следует придать большее значение в качестве подходящего ответа. Я пытался сделать что-то похожее на то, что хочет OP, но сценарии оболочки просто не предназначены для «чистой, ООП-разработки» (ИМХО).
Дэн Л.

4

С помощью case

#!/bin/bash

fun1 () {
    echo "run function1"
    [[ "$@" ]] && echo "options: $@"
}

fun2 () {
    echo "run function2"
    [[ "$@" ]] && echo "options: $@"
}

case $1 in
    fun1) "$@"; exit;;
    fun2) "$@"; exit;;
esac

fun1
fun2

Этот сценарий будет запускать функции fun1 и fun2, но если вы запустите его с опцией fun1 или fun2, он запустит только заданную функцию с аргументами (если предоставлен) и завершится. использование

$ ./test 
run function1
run function2

$ ./test fun2 a b c
run function2
options: a b c

1

Изменить: ПРЕДУПРЕЖДЕНИЕ - похоже, это работает не во всех случаях, но хорошо работает во многих общедоступных скриптах.

Если у вас есть сценарий bash под названием «control», а внутри него есть функция под названием «build»:

function build() { 
  ... 
}

Затем вы можете вызвать его так (из каталога, в котором он находится):

./control build

Если он находится внутри другой папки, это будет:

another_folder/control build

Если ваш файл называется «control.sh», это соответственно сделает функцию вызываемой следующим образом:

./control.sh build

1
У меня это не сработало в интерактивной оболочке. Но это сработало:. ./control.sh && build
saulius2

1

У меня есть ситуация, когда мне нужна функция из сценария bash, который не должен выполняться раньше (например, source), и проблема в @$том, что myScript.sh затем запускается дважды, кажется ... Итак, я пришел к идее чтобы получить функцию с помощью sed:

sed -n "/^func ()/,/^}/p" myScript.sh

И чтобы выполнить его в нужное время, я помещаю его в файл и использую source:

sed -n "/^func ()/,/^}/p" myScript.sh > func.sh; source func.sh; rm func.sh


0

вы можете вызвать функцию из аргумента командной строки, как показано ниже

function irfan() {
echo "Irfan khan"
date
hostname
}
function config() {
ifconfig
echo "hey"
}
$1

как только вы завершите функцию, поместите $ 1 для принятия аргумента, скажем, приведенный выше код сохранен в fun.sh для запуска функции ./fun.sh irfan & ./fun.sh config


0

Решенный пост, но я хотел бы упомянуть свое предпочтительное решение. А именно, определите общий однострочный сценарий eval_func.sh:

#!/bin/bash
source $1 && shift && "@a"

Затем вызовите любую функцию в любом скрипте через:

./eval_func.sh <any script> <any function> <any args>...

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.