Dê uma olhada no código:
#!/bin/bash
read -p "Eneter 1 for UID and 2 for LOGNAME" choice
if [ $choice -eq 1 ]
then
read -p "Enter UID: " uid
logname=`cat /etc/passwd | grep $uid | cut -f1 -d:`
else
read -p "Enter Logname: " logname
fi
not=`ps -au$logname | grep -c bash`
echo "The number of terminals opened by $logname are $not"
Este código é usado para descobrir o número de terminais abertos por um usuário no mesmo PC. Agora, existem dois usuários conectados, digamos x e y. No momento, estou logado como y e há 3 terminais abertos no usuário x. Se eu executar esse código em y usando maneiras diferentes, como mencionado acima, os resultados serão:
$ ./file.sh
The number of terminals opened by x are 3
$ bash file.sh
The number of terminals opened by x are 5
$ sh file.sh
The number of terminals opened by x are 3
$ source file.sh
The number of terminals opened by x are 4
$ . ./file.sh
The number of terminals opened by x are 4
Nota: Passei 1 e uid 1000 para todos esses executáveis.
Agora você pode, por favor, explicar as diferenças entre todos estes?
command-line
bash
scripts
Ramana Reddy
fonte
fonte
Respostas:
A única grande diferença é entre a fonte e a execução de um script.
source foo.sh
irá fornecê-lo e todos os outros exemplos que você mostrar estão executando. Em mais detalhes:./file.sh
Isso executará um script chamado
file.sh
que está no diretório atual (./
). Normalmente, quando você executacommand
, o shell procura nos diretórios do seu$PATH
arquivo executável chamadocommand
. Se você fornecer um caminho completo, como/usr/bin/command
ou./command
, o$PATH
será ignorado e esse arquivo específico será executado.../file.sh
É basicamente o mesmo que,
./file.sh
exceto que, em vez de procurar no diretório atualfile.sh
, ele está procurando no diretório pai (../
).sh file.sh
Isso é equivalente a
sh ./file.sh
, como acima, executará o script chamadofile.sh
no diretório atual. A diferença é que você o está executando explicitamente com osh
shell. Nos sistemas Ubuntu, isso édash
e nãobash
. 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:Esse script simplesmente imprime o nome do shell usado para executá-lo. Vamos ver o que ele retorna quando chamado de maneiras diferentes:
Portanto, a chamada de um script
shell script
substituirá 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:Agora, se eu definir a variável
foo
para outra coisa no shell pai e executar o script, o script imprimirá um valor diferente defoo
(porque também é definido no script), mas o valor defoo
no shell pai não será alterado:No entanto, se eu originar o script em vez de executá-lo, ele será executado no mesmo shell, portanto o valor de
foo
no pai será alterado: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
bash
aparece na saída deps
. 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:E execute-o de várias maneiras, com apenas um único terminal aberto:
Lançamento direto
./foo.sh
,.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 comobash foo.sh
, ele será mostrado apenas como ofoo.sh
que significa que vocêgrep
sentirá 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 ops
comando . 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 queps
mostra sua saída.Lançamento direto com shell explícito (bash)
Aqui, como você está executando
bash foo.sh
, a saída deps
será mostradabash foo.sh
e contada. Portanto, aqui temos o processo pai, abash
execução do script e o shell clonado (executando ops
), todos mostrados porque agoraps
mostrarão cada um deles porque seu comando incluirá a palavrabash
.Lançamento direto com um shell diferente (
sh
)Isso é diferente porque você está executando o script com
sh
e nãobash
. Portanto, a únicabash
instância é o shell pai no qual você iniciou seu script. Todas as outras conchas mencionadas acima estão sendo executadassh
.Sourcing (por
.
ou asource
mesma coisa)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
ps
comando e eleva o total para dois.Como nota final, a maneira correta de contar os processos em execução não é analisar,
ps
mas usá-lapgrep
. Todos esses problemas teriam sido evitados se você tivesse acabado de executarPortanto, uma versão funcional do seu script que sempre imprime o número correto é (observe a ausência de substituição de comando):
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,
sh
pois o processo filho não ébash
.fonte
./foo.sh
é executado em um novo shell que não é uma cópia do pai. Por exemplo, se você definirfoo="bar"
em seu terminal e executar um script que seja executadoecho $foo
, você obterá uma linha vazia, pois o shell do script não herdará o valor da variável.pgrep
é um binário separado e, sim, é executado pelo script que você está executando.