Diferentes maneiras de executar um script de shell

44

Existem várias maneiras de executar um script, as que eu conheço 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 uma e não outra?

    
por phunehehe 11.10.2010 / 12:53

8 respostas

32

Outra maneira é chamar o interpretador e passar o caminho para o script:

/bin/sh /path/to/script

O ponto e a fonte são equivalentes. (EDIT: não, eles não são: como KeithB aponta em um comentário em outra resposta, "." Só funciona em shells relacionadas a bash, onde "source" funciona tanto em shells relacionadas a bash quanto csh). -place (como se você copiou e colou 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 fizer um cd em um diretório, você ainda estará lá quando estiver pronto.

As outras formas de executar um script serão executadas em sua própria sub-rede. Variáveis no script ainda não estão ativas quando é feito. Se o script alterou os diretórios, isso não afeta 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 interpretador diferente do que você faz quando você o executa, então ele pode se comportar de maneira diferente (ou pode não funcionar de todo).

Por exemplo, os scripts Perl e os 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.

O Ubuntu na verdade não usa o shell bash, mas um muito similar chamado dash. Scripts que exigem o bash podem funcionar um pouco errado quando chamados fazendo /bin/sh script , porque você acabou de chamar um script bash usando o interpretador de traço.

Outra pequena diferença entre chamar diretamente o script e passar o caminho do script para o interpretador é que o script deve estar marcado como executável para executá-lo diretamente, mas não para executá-lo passando o caminho para o interpretador.

Outra pequena variação: você pode prefixar qualquer uma destas maneiras de executar um script com eval, então, você pode ter

eval sh script
eval script
eval . script

e assim por diante. Na verdade, isso não muda nada, mas eu pensei em incluí-lo por completo.

    
por 11.10.2010 / 13:07
9

A maioria das pessoas depura scripts de shell adicionando os seguintes 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 tenha permissões para editar o arquivo), adicionando uma linha como set -x , salve o arquivo e execute o arquivo. Então, quando você terminar, precisará seguir as mesmas etapas e remover 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
...
...
    
por 11.10.2010 / 19:56
7

Shawn J. Goff fez muitos pontos positivos, mas não incluiu toda a história:

Ubuntu actually doesn't use the bash shell, but a very similar one called dash. Scripts that require bash may work slightly wrong when called by doing /bin/sh script because you've just called a bash script using the dash interpreter.

Muitos scripts do sistema (como no init.d, em / etc e assim por diante) possuem um shebang #!/bin/sh , mas /bin/sh é de fato um link simbólico para outro shell - em tempos antigos /bin/bash , hoje em dia /bin/dash . Mas quando um deles é invocado como /bin/sh , eles se comportam de maneira diferente, ou seja, eles seguem o modo de compatibilidade POSIX.

Como eles fazem isso? Bem, eles inspecionam como eles foram invocados.

Um próprio shellscript pode testar como foi invocado e fazer coisas diferentes, dependendo disso? Sim pode. Assim, o modo como você o invoca pode sempre levar a resultados diferentes, mas é claro que raramente é feito para incomodar você. :)

Como regra geral: se você estiver aprendendo um shell específico como o bash e escrever comandos a partir de um tutorial bash, coloque #!/bin/bash no título, não #!/bin/sh , exceto onde especificado. Senão seus comandos podem falhar. E se você não tiver escrito um script, chame-o diretamente ( ./foo.sh , bar/foo.sh ) em vez de adivinhar um shell ( sh foo.sh , sh bar/foo.sh ). O shebang deve invocar a casca certa.

E aqui estão dois outros tipos de invocação:

cat foo.sh | dash
dash < foo.sh
    
por 10.02.2011 / 10:24
5

. e source são equivalentes porque não criam 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.

    
por 11.10.2010 / 13:11
2
sh script
bash script

Eu 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 criar 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ê comprá-lo para executá-lo, depois que o script sair, o diretório atual será mantido.

    
por 11.10.2010 / 13:05
1

O " executável userland " conta como um caminho diferente? O userland exec carrega código e faz com que ele seja executado sem o uso de uma chamada de sistema execve ().

    
por 11.10.2010 / 16:43
1
. ./filename
# ( dot space dot slash filename )

Executa o script no shell atual quando o diretório não está no caminho.

    
por 03.11.2010 / 18:17
1

e source são um pouco diferentes em zsh pelo menos (é isso que eu uso) porque

source file

Funciona, enquanto

. file

não precisa de

. ./file
    
por 11.07.2011 / 20:40