Qual é a diferença entre a execução de um script Bash e a fonte?

Respostas:

346

Resposta curta

A fonte de um script executará os comandos no processo atual do shell.

A execução de um script executará os comandos em um novo processo de shell.

Use source se desejar que o script altere o ambiente no shell em execução no momento. use execute caso contrário.

Se você ainda está confuso, continue lendo.

Terminologia

Para esclarecer alguma confusão comum sobre a sintaxe a ser executada e a sintaxe na origem:

./myscript

Isso será executado, myscript desde que o arquivo seja executável e localizado no diretório atual. O ponto inicial e a barra ( ./) denotam o diretório atual. Isso é necessário porque o diretório atual não é geralmente (e geralmente não deve ser) em $PATH.

myscript

Isso será executado myscript se o arquivo for executável e estiver localizado em algum diretório em $PATH.

source myscript

Isso será fonte myscript . O arquivo não precisa ser executável, mas deve ser um script de shell válido. O arquivo pode estar no diretório atual ou em um diretório em $PATH.

. myscript

Isso também será fonte myscript . Essa "ortografia" é a oficial, conforme definido pelo POSIX . Bash definido sourcecomo um alias para o ponto.

Demonstração

Considere myscript.shcom o seguinte conteúdo:

#!/bin/sh
# demonstrate setting a variable
echo "foo: "$(env | grep FOO)
export FOO=foo
echo "foo: "$(env | grep FOO)
# demonstrate changing of working directory
echo "PWD: "$PWD
cd somedir
echo "PWD: "$PWD

Antes de executar o script primeiro, verificamos o ambiente atual:

$ env | grep FOO
$ echo $PWD
/home/lesmana

A variável FOOnão está definida e estamos no diretório inicial.

Agora, executamos o arquivo:

$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Verifique o ambiente novamente:

$ env | grep FOO
$ echo $PWD
/home/lesmana

A variável FOOnão está definida e o diretório de trabalho não foi alterado.

A saída do script mostra claramente que a variável foi configurada e o diretório foi alterado. A verificação depois mostra que a variável não está definida e o diretório não foi alterado. O que aconteceu? As alterações foram feitas em um novo shell. O shell atual gerou um novo shell para executar o script. O script está sendo executado no novo shell e todas as alterações no ambiente entram em vigor no novo shell. Após a conclusão do script, o novo shell é destruído. Todas as alterações no ambiente no novo shell são destruídas com o novo shell. Somente o texto de saída é impresso no shell atual.

Agora nós fonte o arquivo:

$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Verifique o ambiente novamente:

$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir

A variável FOO está definida e o diretório de trabalho foi alterado.

A terceirização do script não cria um novo shell. Todos os comandos são executados no shell atual e as alterações no ambiente entram em vigor no shell atual.

Observe que, neste exemplo simples, a saída da execução é igual à obtenção do script. Este não é necessariamente sempre o caso.

Outra demonstração

Considere o seguinte script pid.sh:

#!/bin/sh
echo $$

(a variável especial se $$expande para o PID do processo atual do shell em execução)

Primeiro imprima o PID do shell atual:

$ echo $$
25009

Origem do script:

$ source pid.sh
25009

Execute o script, observe o PID:

$ ./pid.sh
25011

Fonte novamente:

$ source pid.sh
25009

Execute novamente:

$ ./pid.sh
25013

Você pode ver que a fonte do script é executada no mesmo processo enquanto a execução do script cria um novo processo toda vez. Esse novo processo é o novo shell que foi criado para a execução do script. A terceirização do script não cria um novo shell e, portanto, o PID permanece o mesmo.

Sumário

O fornecimento e a execução do script executarão os comandos no script linha por linha, como se você digitasse esses comandos manualmente, linha por linha.

As diferenças são:

  • Ao executar o script, você está abrindo um novo shell, digite os comandos no novo shell, copie a saída de volta para o shell atual e feche o novo shell. Quaisquer alterações no ambiente entrarão em vigor apenas no novo shell e serão perdidas quando o novo shell for fechado.
  • Quando você origina o script, está digitando os comandos no seu shell atual . Quaisquer alterações no ambiente entrarão em vigor e permanecerão no seu shell atual.

Use source se desejar que o script altere o ambiente no shell em execução no momento. use execute caso contrário.


Veja também:

lesmana
fonte
2
Um uso do sourcing é criar uma forma rudimentar de arquivo de configuração para seus scripts. Você começa definindo várias variáveis ​​para os valores padrão e, em seguida, origina algo como myscript.conf - e esse script de origem pode ter instruções de atribuição que substituem os valores desejados. Como o script de origem não começa com # / bin / bash, não é recomendável executá-lo diretamente.
LawrenceC
Portanto, a fonte é como executá-la em um escopo global e a execução cria um novo escopo local. Isso pode ser estendido para uma função em um script? executar uma função (normalmente) ou "fonte" dela?
precisa saber é o seguinte
2
Existe uma diferença entre usar source myscript.she . myscript.sh?
Holloway
2
praticamente nenhuma diferença se estiver usando o bash. source é um alias para pontuar no bash.
285 lesmana
1
Adoro quando as pessoas fornecem exemplos tão elaborados para que até os novatos no Linux como eu possam entender. Obrigado!
Julius
21

A execução de um script o executa em um processo filho separado, ou seja, uma instância separada do shell é chamada para processar o script. Isso significa que qualquer variável de ambiente etc. definida no script não pode ser atualizada no shell pai (atual).

Fornecer um script significa que ele é analisado e executado pelo próprio shell atual. É como se você digitasse o conteúdo do script. Por esse motivo, o script que está sendo originado não precisa ser executável. Mas deve ser executável se você estiver executando, é claro.

Se você tiver argumentos posicionais no shell atual, eles não serão alterados.

Então, se eu tiver um arquivo a.shcontendo:

echo a $*

e eu faço:

$ set `date`
$ source ./a.sh

Eu recebo algo como:

a Fri Dec 11 07:34:17 PST 2009

Enquanto que:

$ set `date`
$ ./a.sh

me dá:

a

Espero que ajude.

Alok
fonte
5
embora essa resposta esteja correta em todos os aspectos, acho muito difícil de entender porque é demonstrada usando outro conceito (definindo parâmetros posicionais), o que, na minha opinião, é ainda mais confuso do que a diferença de terceirizar e executar.
Lesmana
9

o fornecimento é essencialmente o mesmo que digitar cada linha do script no prompt de comando, uma de cada vez ...

A execução inicia um novo processo e, em seguida, executa cada linha do script, modificando apenas o ambiente atual pelo que ele retorna.

John Weldon
fonte
6

Além disso, a execução do script conforme ./myscriptrequer permissão de execução para o arquivo myscript, enquanto a fonte não requer permissão de execução. É por isso que chmod +x myscriptnão é necessário antessource myscript

abdômen
fonte
2
É verdade, mas se isso é um problema, você sempre pode executar bash myscript.
Daniel Beck
5

No fornecimento, você obtém todas as variáveis ​​extras definidas no script.
Portanto, se você tiver configurações ou definições de funções, deverá originar e não executar. As execuções são independentes do ambiente dos pais.

Arkaitz Jimenez
fonte
3

Se bem me lembro, a execução do script executa o executável na #!linha com o arquivo de script como argumento (normalmente iniciando um novo shell e efetivamente fornecendo o script para o novo shell, como em #!/bin/sh);
enquanto que o fornecimento do script executa cada linha no seu ambiente atual de shell, o que é útil para alterar seu shell atual (por exemplo, fornecendo uma maneira de definir funções de shell e exportar variáveis ​​de ambiente).

Shekhar
fonte
2

sourceO comando executa o script fornecido (a permissão executável não é obrigatória ) no ambiente atual do shell, enquanto ./executa o script executável fornecido em um novo shell.

Além disso, verifique esta resposta, por exemplo: https://superuser.com/a/894748/432100

Harsh Vakharia
fonte