Sim, shells e bash em particular, têm o cuidado de ler o arquivo uma linha de cada vez, por isso funciona da mesma forma que quando você o utiliza interativamente.
Você notará que quando o arquivo não é pesquisável (como um canal), bash até mesmo lê um byte de cada vez para ter certeza de não ler além do caractere \n . Quando o arquivo é procurado, ele otimiza lendo blocos inteiros de cada vez, mas procure novamente após o \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 desse garantia.
Agora, é raro que você queira fazer coisas desse tipo e, como você descobriu, esse recurso tende a atrapalhar mais do que é útil.
Para evitar isso, você pode tentar e não modificar o arquivo no local (por exemplo, modificar uma cópia e mover a cópia no lugar (como sed -i ou perl -pi e alguns editores não por exemplo)).
Ou você pode escrever seu roteiro como:
{
sleep 20
echo test
}; exit
(note que é importante que o exit esteja na mesma linha que } ; embora você também possa colocá-lo dentro das chaves um pouco antes do fechamento).
ou:
main() {
sleep 20
echo test
}
main "$@"; exit
O shell precisará ler o script até o exit antes de começar a fazer qualquer coisa. Isso garante que o shell não irá ler o script novamente.
Isso significa que todo o script 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'
A saída seria U + 00E9 codificada em UTF-8. No entanto, se você alterá-lo para:
{
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
}
O \ue9 será expandido no conjunto de caracteres que estava em vigor no momento em que o comando foi analisado, o que neste caso é anterior ao comando export .
Observe também que, se o comando source aka . for usado, com alguns shells, você terá o mesmo tipo de problema para os arquivos originados.
Esse não é o caso de bash , cujo comando source lê o arquivo totalmente antes de interpretá-lo. Se escrever para bash especificamente, você poderia realmente fazer uso disso, adicionando no início do script:
if [[ ! $already_sourced ]]; then
already_sourced=1
source "$0"; exit
fi
(Eu não confiaria nisso, como você poderia imaginar versões futuras de bash poderiam mudar esse comportamento que pode ser visto atualmente como uma limitação (bash e AT & T ksh são os únicos shells parecidos com POSIX que se comportam) assim, tanto quanto posso dizer) e o truque already_sourced é um pouco frágil, uma vez que assume que a variável não está no ambiente, para não mencionar que ela afeta o conteúdo da variável BASH_SOURCE