Você tem duas maneiras de obter o status de retorno do processo ssh usando os recursos padrão do shell: execute-o de forma síncrona ou chame o wait builtin. Quando você corre
(ssh $userAtServer "ls $targetDir/$targetFile" > $sshOutputFile ; lsReturnValue=$?) &
isso somente define lsReturnValue na subshell, e você não pode obter nenhuma informação diferente do status de retorno para o shell pai. Então você teria que executar exit $lsReturnValue da subshell e obter o status de retorno da subshell do shell pai; e então todo o processo de background poderia ser simplificado para ssh $userAtServer "ls $targetDir/$targetFile" > $sshOutputFile & de qualquer maneira.
Esse trecho de shell que você encontrou para permitir que um comando atinja o tempo limite não é muito bom porque não retém o status de retorno. No Linux, use o utilitário timeout .
Sem o utilitário timeout , fica um pouco complicado. Você precisa executar dois subprocessos: aquele em que está interessado e um que executa sleep para a parte de tempo limite. Se um dos processos retornar, ele deverá matar o outro e permitir que o shell prossiga. Infelizmente, o wait builtin aguarda até que todos os subprocessos tenham morrido quando você o chama sem argumento. Uma maneira de sincronizar os dois processos é fazer com que eles gravem em um pipe e os matem quando aparecerem alguns dados no pipe.
lsReturnValue=$(
{
{ ssh $userAtServer "ls $targetDir/$targetFile" > $sshOutputFile
echo $?; } &
{ sleep 5; echo timeout; } &
} | head -n 1)
if [ "$lsReturnValue" = "timeout" ]; then …
Se você estiver enviando comandos para vários servidores, considere seriamente usar um estrutura multi-servidor ssh como mussh, clusterssh, etc.