A única grande diferença é entre a fonte e a execução de um script. source foo.shirá fornecê-lo e todos os outros exemplos que você mostrar estão executando. Em mais detalhes:
./file.sh
Isso executará um script chamado file.shque está no diretório atual ( ./). Normalmente, quando você executa command, o shell procura nos diretórios do seu $PATHarquivo executável chamado command. Se você fornecer um caminho completo, como /usr/bin/commandou ./command, o $PATHserá ignorado e esse arquivo específico será executado.
../file.sh
É basicamente o mesmo que, ./file.shexceto que, em vez de procurar no diretório atual file.sh, ele está procurando no diretório pai ( ../).
sh file.sh
Isso é equivalente a sh ./file.sh, como acima, executará o script chamado file.shno diretório atual. A diferença é que você o está executando explicitamente com o shshell. Nos sistemas Ubuntu, isso é dashe não bash. Geralmente, os scripts têm uma linha shebang que fornece o programa em que devem ser executados. Chamá-los com um diferente substitui isso. Por exemplo:
$ cat foo.sh
#!/bin/bash
## The above is the shebang line, it points to bash
ps h -p $$ -o args='' | cut -f1 -d' ' ## This will print the name of the shell
Esse script simplesmente imprime o nome do shell usado para executá-lo. Vamos ver o que ele retorna quando chamado de maneiras diferentes:
$ bash foo.sh
bash
$ sh foo.sh
sh
$ zsh foo.sh
zsh
Portanto, a chamada de um script shell scriptsubstituirá a linha shebang (se houver) e executará o script com qualquer shell que você indicar.
source file.sh ou . file.sh
Isso é chamado, surpreendentemente, como fonte do script. A palavra source- chave é um alias para o .comando embutido no shell . Essa é uma maneira de executar o script no shell atual. Normalmente, quando um script é executado, ele é executado em seu próprio shell, que é diferente do atual. Ilustrar:
$ cat foo.sh
#!/bin/bash
foo="Script"
echo "Foo (script) is $foo"
Agora, se eu definir a variável foopara outra coisa no shell pai e executar o script, o script imprimirá um valor diferente de foo(porque também é definido no script), mas o valor de foono shell pai não será alterado:
$ foo="Parent"
$ bash foo.sh
Foo (script) is Script ## This is the value from the script's shell
$ echo "$foo"
Parent ## The value in the parent shell is unchanged
No entanto, se eu originar o script em vez de executá-lo, ele será executado no mesmo shell, portanto o valor de foono pai será alterado:
$ source ./foo.sh
Foo (script) is Script ## The script's foo
$ echo "$foo"
Script ## Because the script was sourced,
## the value in the parent shell has changed
Portanto, o sourcing é usado nos poucos casos em que você deseja que um script afete o shell do qual está sendo executado. Geralmente é usado para definir variáveis de shell e disponibilizá-las após a conclusão do script.
Com tudo isso em mente, a razão pela qual você obtém respostas diferentes é, antes de tudo, que seu script não faz o que você pensa. Conta o número de vezes que bashaparece na saída de ps. Este não é o número de terminais abertos , é o número de shells em execução (na verdade, nem é isso, mas essa é outra discussão). Para esclarecer, simplifiquei um pouco o seu script para isso:
#!/bin/bash
logname=terdon
not=`ps -au$logname | grep -c bash`
echo "The number of shells opened by $logname is $not"
E execute-o de várias maneiras, com apenas um único terminal aberto:
Lançamento direto ./foo.sh,.
$ ./foo.sh
The number of shells opened by terdon is 1
Aqui, você está usando a linha shebang. Isso significa que o script é executado diretamente por tudo o que estiver definido lá. Isso afeta a maneira como o script é mostrado na saída de ps. Em vez de ser listado como bash foo.sh, ele será mostrado apenas como o foo.shque significa que você grepsentirá falta dele. Na verdade, existem três instâncias do bash em execução: o processo pai, o bash executando o script e outro que executa o pscomando . Este último é importante, o lançamento de um comando com substituição de comando ( `command`ou $(command)) resulta em uma cópia do shell pai sendo iniciada e que executa o comando. Aqui, no entanto, nada disso é mostrado devido à maneira que psmostra sua saída.
Lançamento direto com shell explícito (bash)
$ bash foo.sh
The number of shells opened by terdon is 3
Aqui, como você está executando bash foo.sh, a saída de psserá mostrada bash foo.she contada. Portanto, aqui temos o processo pai, a bashexecução do script e o shell clonado (executando o ps), todos mostrados porque agora psmostrarão cada um deles porque seu comando incluirá a palavra bash.
Lançamento direto com um shell diferente ( sh)
$ sh foo.sh
The number of shells opened by terdon is 1
Isso é diferente porque você está executando o script com she não bash. Portanto, a única bashinstância é o shell pai no qual você iniciou seu script. Todas as outras conchas mencionadas acima estão sendo executadas sh.
Sourcing (por .ou a sourcemesma coisa)
$ . ./foo.sh
The number of shells opened by terdon is 2
Como expliquei acima, o fornecimento de um script faz com que ele seja executado no mesmo shell que o processo pai. No entanto, um subshell separado é iniciado para iniciar o pscomando e eleva o total para dois.
Como nota final, a maneira correta de contar os processos em execução não é analisar, psmas usá-la pgrep. Todos esses problemas teriam sido evitados se você tivesse acabado de executar
pgrep -cu terdon bash
Portanto, uma versão funcional do seu script que sempre imprime o número correto é (observe a ausência de substituição de comando):
#!/usr/bin/env bash
user="terdon"
printf "Open shells:"
pgrep -cu "$user" bash
Isso retornará 1 quando originado e 2 (porque um novo bash será lançado para executar o script) para todas as outras formas de lançamento. Ele ainda retornará 1 quando iniciado, shpois o processo filho não é bash.