In Unix, la maggior parte degli editor funziona creando un nuovo file temporaneo contenente i contenuti modificati. Quando il file modificato viene salvato, il file originale viene eliminato e il file temporaneo viene rinominato con il nome originale. (Esistono, ovviamente, varie garanzie per prevenire la perdita di dati.) Questo è, ad esempio, lo stile utilizzato da sed
o perl
quando viene invocato con il -i
flag ("sul posto"), che non è affatto "sul posto". Avrebbe dovuto essere chiamato "nuovo posto con il vecchio nome".
Funziona bene perché unix assicura (almeno per i filesystem locali) che un file aperto continua a esistere fino alla sua chiusura, anche se viene "eliminato" e viene creato un nuovo file con lo stesso nome. (Non è un caso che la chiamata di sistema unix per "eliminare" un file sia in realtà chiamata "unlink".) Quindi, in generale, se un interprete della shell ha un file sorgente aperto e tu "modifichi" il file nel modo sopra descritto , la shell non vedrà nemmeno le modifiche poiché ha ancora il file originale aperto.
[Nota: come per tutti i commenti basati su standard, quanto sopra è soggetto a interpretazioni multiple e ci sono vari casi angolari, come NFS. I pedanti sono invitati a riempire i commenti con eccezioni.]
È ovviamente possibile modificare direttamente i file; non è solo molto conveniente per scopi di modifica, perché mentre puoi sovrascrivere i dati in un file, non puoi eliminare o inserire senza spostare tutti i dati seguenti, il che implicherebbe un sacco di riscrittura. Inoltre, mentre facevi questo spostamento, il contenuto del file sarebbe imprevedibile e i processi con il file aperto ne risentirebbero. Per evitarlo (come per esempio con i sistemi di database), è necessario un sofisticato set di protocolli di modifica e blocchi distribuiti; cose che vanno ben oltre lo scopo di una tipica utility di modifica dei file.
Quindi, se vuoi modificare un file mentre viene elaborato da una shell, hai due opzioni:
È possibile aggiungere al file. Questo dovrebbe sempre funzionare.
È possibile sovrascrivere il file con nuovi contenuti esattamente della stessa lunghezza . Questo potrebbe funzionare o meno, a seconda che la shell abbia già letto o meno quella parte del file. Poiché la maggior parte degli I / O dei file coinvolge i buffer di lettura e poiché tutte le shell che conosco leggono un intero comando composto prima di eseguirlo, è abbastanza improbabile che tu riesca a cavartela. Certamente non sarebbe affidabile.
Non conosco alcuna formulazione nello standard Posix che in realtà richiede la possibilità di aggiungere un file di script mentre il file è in esecuzione, quindi potrebbe non funzionare con ogni shell conforme a Posix, tanto meno con l'attuale offerta di quasi- e shell a volte conformi a posix. Quindi YMMV. Ma per quanto ne so, funziona in modo affidabile con Bash.
Come prova, ecco un'implementazione "senza loop" del famigerato programma 99 bottiglie di birra in bash, che usa dd
per sovrascrivere e aggiungere (la sovrascrittura è presumibilmente sicura perché sostituisce la linea attualmente in esecuzione, che è sempre l'ultima riga del file, con un commento esattamente della stessa lunghezza; l'ho fatto in modo che il risultato finale potesse essere eseguito senza il comportamento di auto-modifica.)
#!/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} #