Existem várias maneiras de executar um script, os que eu sei são:
/path/to/script # using the path (absolute or relative)
. script # using the . (dot)
source script # using the `source` command
São mais disso? Quais são as diferenças entre eles? Existem situações em que devo usar um e não outro?
Outra maneira é chamar o intérprete e passar o caminho para o script:
/bin/sh /path/to/script
O ponto e a fonte são equivalentes. (EDIT: não, não são: como KeithB aponta em um comentário em outra resposta, "." Só funciona em shells relacionados ao bash, onde "source" funciona nos shells relacionados ao bash e csh.) Ele executa o script em -place (como se você tivesse copiado e colado o script ali). Isso significa que quaisquer funções e variáveis não locais no script permanecem. Isso também significa que, se o script gravar um CD em um diretório, você ainda estará lá quando terminar.
As outras maneiras de executar um script o executarão em seu próprio subshell. Variáveis no script ainda não estão ativas quando terminar. Se o script alterou os diretórios, não afetou o ambiente de chamada.
/ path/to/script e/bin/sh script são ligeiramente diferentes. Normalmente, um script tem um "Shebang" no começo que se parece com isso:
#! /bin/bash
Este é o caminho para o interpretador de scripts. Se ele especificar um intérprete diferente do que quando você o executa, ele pode se comportar de maneira diferente (ou pode não funcionar).
Por exemplo, scripts Perl e scripts Ruby começam com (respectivamente):
#! /bin/Perl
e
#! /bin/Ruby
Se você executar um desses scripts executando /bin/sh script
, eles não funcionarão.
Na verdade, o Ubuntu não usa o shell bash, mas um muito semelhante chamado dash. Scripts que requerem bash podem funcionar um pouco errados quando chamados, fazendo /bin/sh script
porque você acabou de chamar um script bash usando o interpretador de traços.
Outra pequena diferença entre chamar o script diretamente e passar o caminho do script para o intérprete é que o script deve ser marcado como executável para executá-lo diretamente, mas não para executá-lo passando o caminho para o intérprete.
Outra variação menor: você pode prefixar qualquer uma dessas maneiras de executar um script com eval, para poder ter
eval sh script
eval script
eval . script
e assim por diante. Na verdade, não muda nada, mas pensei em incluí-lo por completo.
A maioria das pessoas depura scripts do Shell adicionando o seguinte sinalizadores de depuração ao script:
set -x # Print command traces before executing command.
set -v # Prints Shell input lines as they are read.
set -xv # Or do both
Mas isso significa que você precisa abrir o arquivo com um editor (supondo que você tenha permissões para editar o arquivo), adicionando uma linha como set -x
, salve o arquivo e execute-o. Então, quando terminar, siga as mesmas etapas e remova o set -x
, etc. etc. Isso pode ser entediante.
Em vez de fazer tudo isso, você pode definir os sinalizadores de depuração na linha de comando:
$ bash -x ~/bin/ducks
+ du -cks -x dir1 dir2 dir3 file1 file2 file3
+ sort -n
+ tail .ducks
123 etc
424 bin
796 total
$ sh -xv ~/bin/ducks
#!/usr/bin/env bash
# Find the disk hog
# Borrowed from http://oreilly.com/pub/h/15
...
...
Shawn J. Goff fez muitos pontos positivos, mas não incluiu toda a história:
Na verdade, o Ubuntu não usa o shell bash, mas um muito semelhante chamado dash. Scripts que requerem bash podem funcionar um pouco errados quando chamados, fazendo
/bin/sh
script porque você acabou de chamar um script bash usando o interpretador de traços.
Muitos scripts do sistema (como no init.d, no/etc e assim por diante) têm um Shebang #!/bin/sh
, mas /bin/sh
é de fato um link simbólico para outro Shell - em épocas anteriores /bin/bash
, hoje em dia /bin/dash
. Mas quando um deles é chamado como /bin/sh
, eles se comportam de maneira diferente, ou seja, aderem ao modo de compatibilidade com POSIX.
Como eles fazem isso? Bem, eles inspecionam como foram invocados.
O próprio shellscript pode testar como foi chamado e fazer coisas diferentes, dependendo disso? Sim pode. Portanto, a maneira como você o invoca sempre pode levar a resultados diferentes, mas é claro que raramente é feito para incomodá-lo. :)
Como regra geral: se você estiver aprendendo um Shell específico, como o bash, e escrever comandos em um tutorial do bash, coloque #!/bin/bash
no título, não #!/bin/sh
, exceto onde indicado em contrário. Caso contrário, seus comandos podem falhar. E se você não tiver escrito um script, invoque-o diretamente (./foo.sh
, bar/foo.sh
) em vez de adivinhar um Shell (sh foo.sh
, sh bar/foo.sh
). O Shebang deve invocar o Shell certo.
E aqui estão dois outros tipos de invocação:
cat foo.sh | dash
dash < foo.sh
.
e source
são equivalentes, pois não geram um subprocesso, mas executam comandos no Shell atual. Isso é importante quando o script define variáveis de ambiente ou altera o diretório de trabalho atual.
Usando o caminho ou dando a /bin/sh
cria um novo processo no qual os comandos são executados.
sh script
bash script
Estou pensando se há mais ...
.
e source
são iguais. Após a execução, quaisquer alterações de ambiente em script
serão mantidas. Normalmente, ele seria usado para originar uma biblioteca Bash, para que a biblioteca possa ser reutilizada em muitos scripts diferentes.
Também é uma boa maneira de manter o diretório atual. Se você alterar o diretório no script, ele não será aplicado no Shell em que você executa esse script. Mas se você o originar para executá-lo, após a saída do script, o diretório atual será mantido.
. e source são um pouco diferentes no zsh pelo menos (é isso que eu uso) porque
source file
Funciona, enquanto
. file
não precisa
. ./file
. ./filename
# ( dot space dot slash filename )
Executa o script no Shell atual quando o diretório não está no caminho.
" serland exec " conta como uma maneira diferente? O Userland exec carrega o código e o executa sem o uso de uma chamada de sistema execve ().