Usando algum redirecionamento de saída sofisticado, é possível conseguir isso sem o redirecionamento básico do bash para processos.
Registrando erro padrão e mantendo-o no canal de erro padrão
#!/bin/sh
exec 4>&1 # important as it "saves" stdout (usually /dev/tty2 for example)
exec 3>&1 # work-in-progress file descriptor
logfile=/var/log/myscript.out
{
{
date "+%Y-%m-%d %T"
cd $workdir
ls -ltr validfile badfile
} 2>&1 1>&3 | tee -a $logfile 1>&2 2>/dev/null 3>&4
} 3>&1 | tee -a $logfile
exec 4>&- # proper form is to clean up when you're done
exec 3>&-
Explicação:% exec 4>&1
e exec 3>&1
criam novos descritores de arquivo 3 e 4, os quais apontam para qualquer saída padrão que esteja apontando para (seu terminal, provavelmente).
2>&1
redireciona o erro padrão de toda a chave de segundo nível para a saída padrão. 1>&3
redireciona o padrão para o que fd3 está apontando (que é padrão, mas não apenas no canal 1, que é significativo!)
| tee -a $logfile
duplica o padrão in (vindo das chaves de segundo nível, portanto, o stderr antigo) para o arquivo de log e também para o padrão. 1>&2
move padrão para erro padrão (de volta para onde pertence) . 2>/dev/null
provavelmente não é necessário, mas redireciona qualquer saída de erro do tee e trash dele. 3>&4
redireciona o pipe 3 para o pipe 4 (que, por acaso, está apontando para stdout, lembra?).
3>&1
pega o pipe 3 das chaves de primeiro nível e envia para saída padrão regular . | tee -a $logfile
captura a entrada padrão (que é o padrão [ajustado] das chaves) e duplica para o log e para o padrão.