No Unix, a maioria dos editores trabalha criando um novo arquivo temporário que contém o conteúdo editado. Quando o arquivo editado é salvo, o arquivo original é excluído e o arquivo temporário renomeado para o nome original. (Existem, é claro, várias salvaguardas para impedir o dataloss.) Esse é, por exemplo, o estilo usado por sed
ou perl
quando chamado com a -i
bandeira ("in-place"), que não é realmente "in-place". Deveria ter sido chamado de "novo local com nome antigo".
Isso funciona bem porque o unix garante (pelo menos para sistemas de arquivos locais) que um arquivo aberto continue existindo até que seja fechado, mesmo que seja "excluído" e um novo arquivo com o mesmo nome seja criado. (Não é coincidência que a chamada do sistema unix para "excluir" um arquivo seja chamada de "desvincular".) Portanto, de um modo geral, se um interpretador de shell tiver algum arquivo de origem aberto e você "editar" o arquivo da maneira descrita acima , o shell nem verá as alterações, pois ainda possui o arquivo original aberto.
[Nota: como em todos os comentários baseados em padrões, os itens acima estão sujeitos a várias interpretações e existem vários casos de canto, como o NFS. Os pedestres são convidados a preencher os comentários com exceções.]
É claro que é possível modificar arquivos diretamente; simplesmente não é muito conveniente para fins de edição, porque, embora você possa sobrescrever dados em um arquivo, não é possível excluir ou inserir sem alterar todos os dados a seguir, o que implicaria muita reescrita. Além disso, enquanto você fazia essa troca, o conteúdo do arquivo seria imprevisível e os processos que tinham o arquivo aberto seriam prejudicados. Para se livrar disso (como nos sistemas de banco de dados, por exemplo), você precisa de um conjunto sofisticado de protocolos de modificação e bloqueios distribuídos; coisas que estão muito além do escopo de um utilitário típico de edição de arquivos.
Portanto, se você deseja editar um arquivo enquanto este está sendo processado por um shell, você tem duas opções:
Você pode anexar ao arquivo. Isso sempre deve funcionar.
Você pode sobrescrever o arquivo com novos conteúdos exatamente do mesmo comprimento . Isso pode ou não funcionar, dependendo se o shell já leu essa parte do arquivo ou não. Como a maioria das E / S de arquivos envolve buffers de leitura, e como todos os shells que conheço leem um comando composto inteiro antes de executá-lo, é muito improvável que você possa se safar disso. Certamente não seria confiável.
Não conheço nenhuma redação no padrão Posix que realmente exija a possibilidade de anexar a um arquivo de script enquanto o arquivo está sendo executado, portanto, pode não funcionar com todos os shell compatíveis com Posix, muito menos com a oferta atual de quase e conchas às vezes compatíveis com posix. Então YMMV. Mas, tanto quanto eu sei, ele funciona de maneira confiável com o bash.
Como evidência, aqui está uma implementação "sem loop" do infame programa de 99 garrafas de cerveja no bash, que dd
substitui e acrescenta (a substituição é presumivelmente segura porque substitui a linha em execução no momento, que é sempre a última linha do arquivo, com um comentário exatamente do mesmo comprimento; fiz isso para que o resultado final possa ser executado sem o comportamento de modificação automática.)
#!/bin/bash
if [[ $1 == reset ]]; then
printf "%s\n%-16s#\n" '####' 'next ${1:-99}' |
dd if=/dev/stdin of=$0 seek=$(grep -bom1 ^#### $0 | cut -f1 -d:) bs=1 2>/dev/null
exit
fi
step() {
s=s
one=one
case $beer in
2) beer=1; unset s;;
1) beer="No more"; one=it;;
"No more") beer=99; return 1;;
*) ((--beer));;
esac
}
next() {
step ${beer:=$(($1+1))}
refrain |
dd if=/dev/stdin of=$0 seek=$(grep -bom1 ^next\ $0 | cut -f1 -d:) bs=1 conv=notrunc 2>/dev/null
}
refrain() {
printf "%-17s\n" "# $beer bottles"
echo echo ${beer:-No more} bottle$s of beer on the wall, ${beer:-No more} bottle$s of beer.
if step; then
echo echo Take $one down, pass it around, $beer bottle$s of beer on the wall.
echo echo
echo next abcdefghijkl
else
echo echo Go to the store, buy some more, $beer bottle$s of beer on the wall.
fi
}
####
next ${1:-99} #