Bash: Como chamar todas as funções de um arquivo em uma única chamada a partir da linha de comando?

0

Eu uso o Ubuntu 16.04 com o Bash e tenho um arquivo com 10 funções. Cada função faz essencialmente uma tarefa diferente. No final de cada função, eu chamo assim:

x() {
    echo
}
x

As chamadas adicionam mais 10 linhas ao arquivo, linhas que eu gostaria de salvar do arquivo por razões estéticas, porque eu executo todas as funções naquele arquivo (na ordem em que elas já estão classificadas).

Naturalmente, apenas o fornecimento (execução na sessão atual) ou bashing (execução em uma subsessão) não é suficiente (com prazer, porque às vezes se deseja source / bash sem executar todas as funções ).

A solução que eu preferiria para esse problema estético menor seria chamar todas as funções, de alguma forma, diretamente da linha de comando, logo após o sourcing / bashing do arquivo.

É possível no Bash?

    
por user9303970 15.02.2018 / 20:25

4 respostas

2

Se você estiver preocupado apenas com a contagem de linhas do seu arquivo, poderá fazer algo assim:

my_func () {
    echo "Hello, world"
} && my_func
    
por 15.02.2018 / 20:50
2

Você pode usar:

source <(declare -f | grep -o '^[[:alnum:]]\+')

Isso lista todas as definições de função no escopo ( declare -f ) Em seguida, filtra apenas seus nomes, que serão as únicas cadeias alfanuméricas na margem esquerda ( grep -o '^[[:alnum:]]\+' ) e, finalmente, obtém a saída resultante, que é uma lista por linha de nomes de funções, por meio de processo de substituição para que todos sejam chamados no shell atual.

Os itens acima funcionam com GNU ou BSD grep s que possuem -o , mas você pode trocar um comando sed ou awk adequado se necessário.

As funções não estarão em nenhuma ordem particular aqui (a ordem de tabela de hash do Bash, eu acho, que é essencialmente aleatória). Se você precisar preservar um pedido, nomeie-o adequadamente e adicione um sort no meio:

source <(declare -f | grep -o '^[[:alnum:]]\+'|sort)

Se as funções em si são destinadas a serem chamadas independentemente, essa estrutura de nomes pode ser indesejável. Eu não vejo uma maneira simples de contornar isso.

Isso funciona dentro de um único arquivo. Se você estiver fazendo o sourcing do arquivo em um shell que já tem funções definidas nele, é necessário lembrar quais já existem e ignorá-los:

funcs=($(declare -f | grep -o '^[[:alnum:]]\+'|sort))
source file
source <(declare -f | grep -o '^[[:alnum:]]\+' | sort - <(printf '%s\n' "${funcs[@]}" | uniq -u)

Existem várias maneiras de fazer isso, todas as quais são bastante estranhas. Isso também cai quando você redefine uma função existente. Outra abordagem seria grep out todas as linhas de definição de função do próprio arquivo; se você está estruturado sobre como você escreve, isso funciona também.

Uma abordagem possivelmente melhor, se você controlar o conteúdo do arquivo, seria listar os nomes das funções, na ordem que você deseja que sejam chamados, em uma definição de matriz de linha única na parte inferior do arquivo. Então você pode passar por ele na shell de sourcing e fazer o que você precisa.

Esta abordagem seria mais clara e menos frágil. No entanto, introduz a possibilidade de os dois locais ficarem fora de sincronia.

    
por 15.02.2018 / 21:04
1

Se você realmente quer um one-liner, eu criei isto, assumindo um arquivo scripts/1.sh :

shopt -s extdebug; source scripts/1.sh; source="$_"; while IFS= read -r func; do declare_output="$(declare -F "${func##* }")"; [[ ${declare_output##* } == $source ]] && "${func##* }"; done < <(declare -F)

Basicamente, isso usa declare para determinar quais funções em seu ambiente vieram do arquivo originado e as executam. Eu tenho três funções em scripts/1.sh , que echo Goodbye , cruel e world. , e minha saída desse comando é:

Goodbye,
cruel
world.

Eu não sei se a ordem da saída declare é garantida como a ordem em que as funções foram originadas, então você pode ter que nomear as funções apropriadamente e usar sort .

    
por 15.02.2018 / 22:49
1

Eu sugiro manter as chamadas explícitas, por vários motivos. Eles permitem que você remova temporariamente algumas funções da lista de chamadas, altere a ordem, mantenha versões antigas das funções durante a edição e tenha funções de utilidade que são chamadas apenas de outras funções (mas não do nível "principal"). O último em particular parece importante para a adequada estruturação do programa.

Mas se você realmente quiser, você pode fazer isso. Embora eu possa sugerir, pelo menos, adicionar algum tipo de designador para as funções autorunnable. Parcialmente baseado no comentário de @ cas, este executa todas as funções marcadas com # AUTORUN na linha acima.

#!/bin/bash

foo() { echo foo; }

# AUTORUN
bar() { echo bar; }

while IFS= read -r f; do
    $f
done < <(sed -nE '/^# *AUTORUN/!d; n; s/^([a-zA-Z0-9_]+) *\(\).*//p' "${BASH_SOURCE[0]}")

Provavelmente precisa do GNU sed no formulário atual.

    
por 16.02.2018 / 16:53