A variável $!
do shell só conhece o pid do processo iniciado pelo shell. Como você suspeitava, a chamada ssh
usando -f
bifurca seu próprio processo para que ele possa ir para o plano de fundo, portanto, a árvore do processo geral se parece com [1]:
shell
|
+--ssh<1> (pid is $!)
|
+--ssh<2> (pid is different)
ssh<1>
sai muito pouco depois da invocação; portanto, é improvável que o valor em $!
seja útil. É ssh<2>
que está realizando a comunicação remota e fazendo seu tunelamento para você, e a única maneira de obter seu PID de forma confiável é examinando a tabela de processos, como você está fazendo com pgrep
[2]. O método pgrep
provavelmente será o correto aqui.
Por que funciona no script, mas não de forma interativa, essa é provavelmente uma condição de corrida. Como você coloca o primeiro ssh
em segundo plano, o shell e o ssh
estão sendo executados simultaneamente, e ssh
faz algumas autenticações criptográficas com CPU moderada e algumas viagens de ida e volta na rede. É provável que o pgrep
que você executa no script esteja sendo executado antes que ssh<1>
se forme para ir para o segundo plano. Para contornar isso, execute pgrep
mais tarde, seja por uma chamada sleep
, ou apenas ligando apenas quando você realmente precisar do PID mais tarde.
[1]: Tecnicamente, pode ser mais complicado do que isso, se ssh
estiver usando um plano duplo clássico como plano de fundo. Nesse caso, haveria outro processo efêmero de ssh
entre os dois.
[2]: A menos que você seja systemd
e esteja usando cgroups ou algo para acompanhar todos os seus filhos. Que você não é.