Sim, os shells e, bashem particular, são cuidadosos ao ler o arquivo uma linha de cada vez, para que funcione da mesma maneira que quando você o usa interativamente.
Você notará que, quando o arquivo não é procurável (como um pipe), ele bashlê um byte de cada vez para ter certeza de não ler além do \ncaractere. Quando o arquivo é procurável, ele otimiza lendo blocos inteiros de cada vez, mas procura novamente após o arquivo \n.
Isso significa que você pode fazer coisas como:
bash << \EOF
read var
var's content
echo "$var"
EOF
Ou escreva scripts que se atualizem. O que você não seria capaz de fazer se não lhe desse essa garantia.
Agora, é raro que você queira fazer coisas assim e, como você descobriu, esse recurso tende a atrapalhar com mais frequência do que é útil.
Para evitá-lo, você pode tentar garantir que não modifique o arquivo no local (por exemplo, modifique uma cópia e mova a cópia no local (como sed -iou perl -pialguns editores fazem, por exemplo)).
Ou você pode escrever seu script como:
{
sleep 20
echo test
}; exit
(observe que é importante que exitesteja na mesma linha que }; embora você também possa colocá-lo dentro do aparelho antes do fechamento).
ou:
main() {
sleep 20
echo test
}
main "$@"; exit
O shell precisará ler o script até exitantes de começar a fazer qualquer coisa. Isso garante que o shell não leia novamente o script.
Isso significa que o script inteiro será armazenado na memória.
Isso também pode afetar a análise do script.
Por exemplo, em bash:
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
Saída que U + 00E9 codificado em UTF-8. No entanto, se você alterar para:
{
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
}
O \ue9será expandido no conjunto de caracteres que estava em vigor no momento em que o comando foi analisado, o que, neste caso, é antes do exportcomando ser executado.
Observe também que, se o comando sourceaka .for usado, com algumas conchas, você terá o mesmo tipo de problema para os arquivos de origem.
Não é esse o caso de bashcujo sourcecomando lê o arquivo completamente antes de interpretá-lo. Se você escrever bashespecificamente, poderá usar isso adicionando no início do script:
if [[ ! $already_sourced ]]; then
already_sourced=1
source "$0"; exit
fi
(Eu não confiaria nisso, pois, como você pode imaginar, as versões futuras bashpodem mudar esse comportamento que atualmente pode ser visto como uma limitação (o bash e o AT&T ksh são os únicos shells do tipo POSIX que se comportam dessa maneira até onde se sabe) e o already_sourcedtruque é um pouco frágil, pois supõe que a variável não está no ambiente, sem mencionar que afeta o conteúdo da variável BASH_SOURCE)