Eu estava escrevendo um script bash e atualizei o código (salvou o arquivo de script em disco) enquanto o script aguardava alguma entrada em um while
loop. Depois que voltei ao terminal e continuei com a invocação anterior do script, o bash deu um erro sobre a sintaxe do arquivo:
/home/aularon/bin/script: line 58: unexpected EOF while looking for matching `"'
/home/aularon/bin/script: line 67: syntax error: unexpected end of file
Então, tentei fazer o seguinte:
1º: crie um script, self-update.sh
vamos chamá-lo:
#!/bin/bash
fname=$(mktemp)
cat $0 | sed 's/BEFORE\./AFTER!./' > $fname
cp $fname $0
rm -f $fname
echo 'String: BEFORE.';
O que o script faz é ler seu código, alterar a palavra 'ANTES' para 'APÓS' e depois reescrever-se com o novo código.
2º Execute:
chmod +x self-update.sh
./self-update.sh
3ª maravilha ...
aularon@aularon-laptop:~$ ./self-update.sh
String: AFTER!.
Agora, eu não teria imaginado que, na mesma invocação, sairia DEPOIS! , na segunda execução, com certeza, mas não na primeira.
Então, minha pergunta é: é intencional (por design)? ou é por causa da maneira como o bash executa o script? Linha por linha ou comando por comando. Existe algum bom uso desse comportamento? Algum exemplo disso?
Edit: Eu tentei reformatar o arquivo para colocar todos os comandos em uma linha, ele não funciona agora:
#!/bin/bash
fname=$(mktemp);cat $0 | sed 's/BEFORE\./AFTER!./' > $fname;cp $fname $0;rm -f $fname;echo 'String: BEFORE.';
Resultado:
aularon@aularon-laptop:~$ ./self-update.sh #First invocation
String: BEFORE.
aularon@aularon-laptop:~$ ./self-update.sh #Second invocation
String: AFTER!.
Ao mover a echo
string para a próxima linha, separe-a da cp
chamada rewriting ( ):
#!/bin/bash
fname=$(mktemp);cat $0 | sed 's/BEFORE\./AFTER!./' > $fname;cp $fname $0;rm -f $fname;
echo 'String: BEFORE.';
E agora funciona novamente:
aularon@aularon-laptop:~$ ./self-update.sh
String: AFTER!.
Respostas:
Isso ocorre por design. Bash lê scripts em pedaços. Portanto, ele lerá uma parte do script, executará todas as linhas que puder e, em seguida, lerá a próxima parte.
Então você encontra algo assim:
Onde isso se torna ainda mais problemático é que, se você editar qualquer coisa antes do byte 256. Digamos que você exclua algumas linhas. Em seguida, os dados no script que estava no byte 256 agora estão em outro lugar, digamos no byte 156 (100 bytes antes). Por esse motivo, quando o bash continuar lendo, ele obterá o que era originalmente 356.
Este é apenas um exemplo. O Bash não lê necessariamente 256 bytes de cada vez. Não sei exatamente quanto ele lê ao mesmo tempo, mas não importa, o comportamento ainda é o mesmo.
fonte
stat
o arquivo para ver se ele foi alterado. Semlseek
chamadas.echo foo
mudou para aecho bar
durante osleep
. Ele está se comportando assim desde as versões 2, então não acho que seja um problema de versão.