Como posso executar uma função de um script na linha de comando?


119

Tenho um script que tem algumas funções.

Posso executar uma das funções diretamente da linha de comando?

Algo assim?

myScript.sh func()

Respostas:


66

Se o script apenas definir as funções e não fizer mais nada, você pode primeiro executar o script dentro do contexto do shell atual usando o comando sourceou .e, em seguida, simplesmente chamar a função. Veja help sourcepara mais informações.


1
O único problema com esse método é que se você usar exitem sua função, ele fechará o terminal após a execução da função. Existe alguma maneira de contornar isso? @SvenMarnach
user1527227

@ user1527227: Vá com a próxima resposta nesse caso, desde que você tenha controle do script de shell. Caso contrário, você pode chamar um subshell interativo primeiro (basta inserir bash) e exitsó encerrará o subshell, mas não seu terminal.
Sven Marnach

238

Bem, enquanto as outras respostas estão certas - você certamente pode fazer outra coisa: se você tiver acesso ao script bash, você pode modificá-lo e simplesmente colocar no final o parâmetro especial "$@"- que se expandirá para os argumentos da linha de comando você especifica e, como está "sozinho", o shell tentará chamá-los literalmente; e aqui você pode especificar o nome da função como o primeiro argumento. Exemplo:

$ 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

Para polir, você pode primeiro verificar se o comando existe e é uma função:

# 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
Use "$@"na maioria dos casos. $@não é seguro em alguns casos.
fumiyas de

1
Como executar mais do que uma função? por exemplo, posso correr bash test.sh testA testB?
Jeff Pang

Isso também precisa ser embrulhado, [ ! -z "$1" ]caso contrário, a fonte levantará a instrução else em algumas
versões do

Tenho pesquisado de perto e de longe por esta variável "$ @" mágica para usar qualquer função que seja chamada em um arquivo, obrigado @sdaau!
Justin Hammond

36

O comando a seguir primeiro registra a função no contexto e a chama:

. ./myScript.sh && function_name

1
Você também pode simplesmente usar a fonte. Como em - fonte myScript.sh && function_name
stolen_leaves

17

Resumidamente, não.

Você pode importar todas as funções do script para o seu ambiente com source( help sourcepara obter detalhes), o que permitirá que você as chame. Isso também tem o efeito de executar o script, portanto, tome cuidado.

Não há como chamar uma função de um script de shell como se fosse uma biblioteca compartilhada.


1
Acho que isso deveria receber mais peso como uma resposta apropriada. Tentei fazer algo semelhante ao que o OP deseja, mas o script de shell simplesmente não foi projetado para "desenvolvimento limpo e OOP" (IMHO).
Dan L

4

Usando 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

Este script executará as funções fun1 e fun2, mas se você iniciá-lo com a opção fun1 ou fun2, ele apenas executará a função dada com args (se fornecida) e sairá. Uso

$ ./test 
run function1
run function2

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

1

Editar: AVISO - parece que isso não funciona em todos os casos, mas funciona bem em muitos scripts públicos.

Se você tem um script bash chamado "control" e dentro dele você tem uma função chamada "build":

function build() { 
  ... 
}

Então você pode chamá-lo assim (do diretório onde está):

./control build

Se estiver dentro de outra pasta, isso o tornaria:

another_folder/control build

Se o seu arquivo for chamado "control.sh", isso tornaria a função chamável assim:

./control.sh build

1
Isso não funcionou no shell interativo para mim. Mas funcionou:. ./control.sh && build
saulius2

1

Tenho uma situação em que preciso de uma função do script bash que não deve ser executada antes (por exemplo, por source) e o problema @$é que myScript.sh é executado duas vezes, parece ... Então, tive a ideia para obter a função com sed:

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

E para executá-lo na hora que preciso, coloco em um arquivo e uso source:

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


0

você pode chamar a função a partir do argumento da linha de comando como abaixo

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

assim que a função end coloque $ 1 para aceitar o argumento, digamos que o código acima seja salvo em fun.sh para executar a função ./fun.sh irfan & ./fun.sh config


0

Postagem resolvida, mas gostaria de mencionar minha solução preferida. Ou seja, defina um script genérico de uma linha eval_func.sh:

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

Em seguida, chame qualquer função em qualquer script por meio de:

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

Um problema que encontrei com a solução aceita é que, ao buscar meu script que contém a função em outro script, os argumentos do último seriam avaliados pelo primeiro, causando um erro.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.