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