Como definir um script de shell para ser originado não executado

33

Estou definindo um script de shell que um usuário deve source em vez de executar.

Existe uma maneira convencional ou inteligente de sugerir ao usuário que esse é o caso, por exemplo, por meio de uma extensão de arquivo?

Existe código de shell que eu posso escrever no próprio arquivo, o que fará com que ele ecoe uma mensagem e saia se for executado em vez de sourced, para que eu possa ajudar o usuário a evitar esse erro óbvio?

    
por algal 16.02.2018 / 00:05

5 respostas

42

Assumindo que você está executando o bash, coloque o seguinte código próximo ao início do script que você quer que seja originado, mas não executado:

if [ "${BASH_SOURCE[0]}" -ef "$0" ]
then
    echo "Hey, you should source this script, not execute it!"
    exit 1
fi

No bash, ${BASH_SOURCE[0]} conterá o nome do arquivo atual que o shell está lendo, independentemente de estar sendo originado ou executado.

Por contraste, $0 é o nome do arquivo atual que está sendo executado.

-ef testa se esses dois arquivos são o mesmo arquivo. Se estiverem, alertamos o usuário e saímos.

Nem -ef nem BASH_SOURCE são POSIX. Enquanto -ef é suportado por ksh, yash, zsh e Dash, BASH_SOURCE requer bash. Em zsh , no entanto, ${BASH_SOURCE[0]} pode ser substituído por ${(%):-%N} .

    
por 16.02.2018 / 00:23
32

Um arquivo não executável pode ser originado, mas não executado, portanto, como primeira linha de defesa, não configurar o sinalizador de executável deve ser uma boa dica.

    
por 16.02.2018 / 00:37
9

Existem vários métodos sugeridos em esta postagem sobre estouro de pilha , dos quais gostei da baseada em funções sugerida por Wirawan Purwanto e mr.spuratic melhor:

The most robust way, as suggested by Wirawan Purwanto, is to check FUNCNAME[1] within a function:

function mycheck() { declare -p FUNCNAME; }
mycheck

Then:

$ bash sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="main")'
$ . sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="source")'

This is the equivalent to checking the output of caller, the values main and source distinguish the caller's context. Using FUNCNAME[] saves you capturing and parsing caller output. You need to know or calculate your local call depth to be correct though. Cases like a script being sourced from within another function or script will cause the array (stack) to be deeper. (FUNCNAME is a special bash array variable, it should have contiguous indexes corresponding to the call stack, as long as it is never unset.)

Você pode adicionar ao início do script:

function check()
{
    if [[ ${FUNCNAME[-1]} != "source" ]]   # bash 4.2+, use ${FUNCNAME[@]: -1} for older
    then
        printf "Usage: source %s\n" "$0"
        exit 1
    fi
}
check
    
por 16.02.2018 / 09:19
7

Assumindo que é inútil, e não prejudicial, executar o script, você pode adicionar

return 0 || printf 'Must be sourced, not executed\n' >&2

para o fim do script. return fora de uma função possui um código de saída diferente de zero, a menos que o arquivo esteja sendo originado.

    
por 16.02.2018 / 17:54
4

Quando você obtém um script de shell, a linha shebang é ignorada. Ao inserir uma declaração inválida, você pode alertar o usuário de que o script foi executado incorretamente:

#!/bin/bash source-this-script
# ...

A mensagem de erro será esta:

/bin/bash: source-this-script: No such file or directory

O nome do argumento (arbitrário) já fornece uma dica strong, mas a mensagem de erro ainda não está 100% clara. Podemos corrigir isso com um script de utilitário source-this-script , que é colocado em algum lugar no seu PATH :

#!/bin/sh
echo >&2 "This script must be sourced, not executed${1:+: }${1:-!}"
exit 1

Agora, a mensagem de erro será esta:

This script must be sourced, not executed: path/to/script.sh

Comparação com outras abordagens

Em comparação com as outras respostas, essa abordagem requer apenas alterações mínimas em cada script (e ter uma linha shebang ajuda na detecção do tipo de arquivo nos editores e especifica o dialeto do shell script, para que haja benefícios). A desvantagem é uma mensagem de erro pouco clara ou a adição (única) de outro script de shell.

Isso não impede a invocação explícita via bash path/to/script.sh (obrigado @muru!).

    
por 16.02.2018 / 10:01

Tags