Por que o comando “source” do Bash se comporta de maneira diferente quando chamado de uma função?

4

Tendo em conta o seguinte script de bar Bash ...

echo :$#:"$@":

... e o seguinte script executável foo Bash:

echo -n source bar:
source bar
echo -n source bar foo:
source bar foo

function _import {
  source "$@"
}

echo -n _import bar:
_import bar
echo -n _import bar foo:
_import bar foo

Eu recebo a seguinte saída ao executar o script foo Bash, por exemplo, ./foo :

source bar::0::
source bar foo::1:foo:
_import bar::1:bar:
_import bar foo::1:foo:

Aqui estão minhas perguntas:

  1. Por que faz diferença quando eu chamo o comando source do Bash da função _import ao invés de diretamente?
  2. Como posso normalizar o comportamento do comando source do Bash?

Estou usando a versão 4.2.47 (1) do Bash - lançada na versão 20 do Fedora.

    
por Tim Friske 24.08.2014 / 12:03

2 respostas

3

A resposta de Gnouc explica minha primeira pergunta: "Por que faz diferença quando eu chamo o comando de fonte do Bash da função _import ao invés de diretamente?"

Com relação à minha segunda pergunta: "Como posso normalizar o comportamento do comando de origem do Bash?"

Acho que encontrei a seguinte resposta:

Alterando a função _import para:

function _import {
  local -r file="$1"
  shift
  source "$file" "$@"
}

Eu recebo a seguinte saída ao executar o script foo Bash, por exemplo, ./foo :

source bar::0::
source bar foo::1:foo:
_import bar::0::
_import bar foo::1:foo:

Justificativa por trás da minha pergunta e esta resposta: Um script Bash "importado" deve ser capaz de avaliar seu próprio conjunto de argumentos através dos parâmetros posicionais e especiais do Bash mesmo quando nenhum foi dado durante a importação. Quaisquer argumentos que PODEM ser passados para o script de Bash de importação NÃO DEVEM ser implicitamente passados para o script de Bash importado.

    
por 24.08.2014 / 13:06
4

O problema porque source executa o arquivo no ambiente atual. E em bash , se nenhum parâmetro posicional for fornecido, eles permanecerão inalterados. De bash Bourne Shell Builtins homem página:

. (a period)

. filename [arguments]

Read and execute commands from the filename argument in the current shell context. If filename does not contain a slash, the PATH variable is used to find filename. When Bash is not in POSIX mode, the current directory is searched if filename is not found in $PATH. If any arguments are supplied, they become the positional parameters when filename is executed. Otherwise the positional parameters are unchanged. The return status is the exit status of the last command executed, or zero if no commands are executed. If filename is not found, or cannot be read, the return status is non-zero. This builtin is equivalent to source.

POSIX define ponto ( source é sinônimo de dot in bash ):

The shell shall execute commands from the file in the current environment.

E também explicou que a versão do ponto do KornShell pode pegar argumentos opcionais, que são configurados para os parâmetros posicionais:

The KornShell version of dot takes optional arguments that are set to the positional parameters. This is a valid extension that allows a dot script to behave identically to a function.

Portanto, quando você chamar a função source bar dentro de _import , você não fornecerá nenhum parâmetro posicional, portanto eles não serão alterados. Eles são idênticos ao escopo da função _import , $@ contém bar e $# é 1 (porque você executa _import bar ).

Quando você chama o escopo de função source bar outside _import , ele é idêntico ao escopo global (ou foo script). Nesse caso, como você executa ./foo , você executa foo sem nenhum argumento, $@ é nulo e $# é zero.

    
por 24.08.2014 / 12:42