Come viene eseguita la modifica sul posto di un file?


10

Che cosa significa la modifica "inplace" di un file, ad esempio tramite sed -io perl -isignifica?
La mia domanda è su come viene effettuata questa modifica sul posto. Il file viene copiato, la modifica viene eseguita nella copia e quindi sostituisce l'originale? O il file originale viene in qualche modo modificato in atto?


Dai un'occhiata a backreference.org/2011/01/29/in-place-editing-of-files per una spiegazione dettagliata di questo argomento.
scy

Del resto, come si fa con exo vi?
Wildcard il

@Wildcard - ognuno di questi ha un intero sistema in atto. exmantiene un file di posta (come, dead.mailo qualcosa in ~ te, e un altro da qualche parte vicino allo spooler di posta, di solito) . controlla le specifiche - ognuna di esse ha uno stato definito a grandi lunghezze ... exha il suo formato binario nella maggior parte dei casi (guarda il tuo -rescuefile) e questo è usato per prezero separare i file temporanei del buffer (possibilmente fino a sei) . quindi questi blocchi di input di copia per modificare i buffer e sincronizzare le scritture in offset per modifiche :!written?
Mikeserv,

Risposte:


18

sed crea un file temporaneo, scrive l'output in quel file e quindi rinomina il file temporaneo sopra l'originale.

Puoi vedere cosa succede usando strace:

$ strace -e trace=file sed -i -e '' a
execve("/usr/bin/sed", ["sed", "-i", "-e", "", "a"], [/* 34 vars */]) = 0
<...trimmed...>
open("a", O_RDONLY)                     = 3
open("./sedxvhRY8", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
rename("./sedxvhRY8", "a")              = 0
+++ exited with 0 +++

In questo modo vengono registrate tutte le operazioni sui file sed: crea un nuovo file (in modo sicuro con O_CREAT|O_EXCL), scrive i dati in esso e quindi li sposta di nuovo sopra il mio file originale a.

sed -iaccetta un suffisso da utilizzare per un backup e in tal caso sposta prima l'originale (anziché rinominarlo in alto). Tale argomento è obbligatorio nella maggior parte dei BSD sed. In questo caso, c'è un breve periodo in cui non ci sono file con il nome giusto nella directory.

perl nelle versioni recenti apre il file di input, quindi lo elimina e crea un nuovo file con lo stesso nome:

open("a", O_RDONLY)               = 3
unlink("a")                       = 0
open("a", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4

Quando elimini ( unlink) un file che hai già aperto, ne conservi l'accesso fintanto che mantieni il punto di controllo, in modo che possa continuare a leggere i dati dal file eliminato. In questo modo perlscrive direttamente nel file di output, piuttosto che in un file temporaneo: non viene creato alcun file aggiuntivo, ma se si legge il file durante il processo si otterrà un contenuto parziale, diversamente seddall'approccio. C'è anche un breve periodo in cui non esiste un file con il nome giusto, che è all'inizio del processo piuttosto che alla fine (come in sed -i .bak).


Entrambi sede perlvolontà:

  • Sostituisci un collegamento simbolico con un file normale.
  • Rompere i collegamenti duri.
  • Preservare la proprietà del gruppo, se possibile.
  • Crea il file con il tuo gruppo predefinito (o il gruppo della directory padre se quella directory ha il setgidbit) se era di proprietà di un gruppo in cui non sei e non sei root.
  • Mantieni la proprietà dei file se sei root.
  • Conserva le autorizzazioni di base.
  • Conserva setuide setgrpbit, se il gruppo risultante è uguale al gruppo nel quale è stato avviato.
  • Preservare la parte adesiva.
  • Non conservare xattrs.

sed volontà:

  • Preservare gli ACL (su Linux; non conosco altri) .

perl volontà:

  • Non conservare ACL.

Quanto sopra è vero su Linux con GNU sede Mac OS X con i suoi (derivati ​​da FreeBSD) sed.


3

In aggiunta alla risposta di @ Homer, da perldoc perlrun:

specifica che i file elaborati dal costrutto "<>" devono essere modificati sul posto. Lo fa rinominando il file di input, aprendo il file di output con il nome originale e selezionando quel file di output come predefinito per le istruzioni print (). L'estensione, se fornita, viene utilizzata per modificare il nome del vecchio file per creare una copia di backup, seguendo queste regole:

Se non viene fornita alcuna estensione, non viene eseguito alcun backup e il file corrente viene sovrascritto.

Se l'estensione non contiene un *, viene aggiunto alla fine del nome file corrente come suffisso. Se l'estensione contiene uno o più * caratteri, ciascuno * viene sostituito con il nome file corrente.

E ricorda che non viene conservato alcun collegamento soft o hard link:

Si noti che poiché -i rinomina o elimina il file originale prima di creare un nuovo file con lo stesso nome, i collegamenti soft e hard in stile UNIX non verranno conservati.

Infine, l'opzione -i non impedisce l'esecuzione quando non viene fornito alcun file sulla riga di comando. In questo caso, non viene eseguito alcun backup (il file originale non può, ovviamente, essere determinato) e l'elaborazione procede da STDIN a STDOUT come ci si potrebbe aspettare.

Questo spiega anche perché è necessario utilizzare -icon l' -popzione o utilizzare printun'istruzione esplicita se si desidera modificare sul posto con perl:

# Opps, file will be truncated, becomes empty
$ perl -i.bak -ne 's/123/qwe/' file

# Right way
$ perl -i.bak -ne 's/123/qwe/;print' file

# Or
$ perl -i.bak -pe 's/123/qwe/' file
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.