Comment se fait la modification sur place d'un fichier?

10

Que signifie la modification "sur place" d'un fichier, par exemple via sed -iou perl -isignifie?
Ma question est de savoir comment cette modification sur place est effectuée. Le fichier est-il copié, la modification est effectuée dans la copie, puis remplace l'original? Ou est-ce que le fichier d'origine est en quelque sorte modifié en place?

Jim
la source
Jetez un œil à backreference.org/2011/01/29/in-place-editing-of-files pour une explication détaillée de ce sujet.
scy
D'ailleurs, comment est-il fait avec exou vi?
Wildcard
@Wildcard - chacun d'eux a un système entier en place. exmaintient un fichier courrier (comme, dead.mailou quelque chose en vous, et un autre quelque part près de votre spouleur de messagerie, généralement) . vérifiez les spécifications - chacun d'entre eux a un état défini à de grandes longueurs ... exa son propre format binaire dans la plupart des cas (regardez votre -rescuefichier) et celui-ci est utilisé pour prérégler des fichiers tampons temporaires séparés (peut-être jusqu'à six) . donc ceux-ci copient les blocs d'entrée pour éditer les tampons et les écritures de synchronisation dans les décalages par changement :!written?
mikeserv

Réponses:

18

sed crée un fichier temporaire, écrit la sortie dans ce fichier, puis renomme le fichier temporaire par-dessus l'original.

Vous pouvez regarder ce qui se passe en utilisant 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 +++

Cela enregistre toutes les opérations sur les fichiers sed: il crée un nouveau fichier (en toute sécurité avec O_CREAT|O_EXCL), y écrit les données, puis le remonte par-dessus mon fichier d'origine a.

sed -iaccepte un suffixe à utiliser pour une sauvegarde, et dans ce cas, il déplace l'original à l'écart en premier (plutôt que de le renommer par-dessus). Cet argument est obligatoire dans la plupart des BSD sed. Dans ce cas, il y a un bref moment où il n'y a aucun fichier du bon nom dans le répertoire.

perl dans les versions récentes, ouvre le fichier d'entrée, puis le supprime et crée un nouveau fichier du même nom:

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

Lorsque vous supprimez ( unlink) un fichier que vous avez déjà ouvert, vous conservez l'accès à celui-ci aussi longtemps que vous gardez la poignée, afin qu'il puisse continuer à lire les données du fichier supprimé. De cette façon, perlécrit directement dans le fichier de sortie, plutôt que dans un fichier temporaire: aucun fichier supplémentaire n'est créé, mais si vous lisez le fichier pendant le processus, vous obtiendrez un contenu partiel, contrairement à sedl'approche de. Il y a aussi un bref moment où il n'y a pas de fichier avec le bon nom, qui est au début du processus plutôt qu'à la fin (comme dans sed -i .bak).


Les deux sedet perl:

  • Remplacez un lien symbolique par un fichier ordinaire.
  • Brisez les liens durs.
  • Préservez la propriété du groupe si possible.
  • Créez le fichier avec votre groupe par défaut (ou le groupe du répertoire parent si ce répertoire contient le setgidbit) s'il appartenait à un groupe dans lequel vous n'êtes pas et que vous n'êtes pas root.
  • Préservez la propriété des fichiers si vous êtes root.
  • Conserver les autorisations de base.
  • Préserver setuidet setgrpbits, si le groupe résultant est le même que le groupe dans lequel il a commencé.
  • Conservez le peu collant.
  • Ne préserve pas les xattrs.

sed volonté:

  • Préserver les ACL (sous Linux; je ne connais pas les autres) .

perl volonté:

  • Ne conserve pas les ACL.

Ce qui précède est vrai sur Linux avec GNU sedet Mac OS X avec son (dérivé de FreeBSD) sed.

Michael Homer
la source
3

En plus de la réponse de @ Homer, de perldoc perlrun:

spécifie que les fichiers traités par la construction "<>" doivent être modifiés sur place. Il le fait en renommant le fichier d'entrée, en ouvrant le fichier de sortie par le nom d'origine et en sélectionnant ce fichier de sortie par défaut pour les instructions print (). L'extension, si elle est fournie, est utilisée pour modifier le nom de l'ancien fichier pour effectuer une copie de sauvegarde, en suivant ces règles:

Si aucune extension n'est fournie, aucune sauvegarde n'est effectuée et le fichier actuel est écrasé.

Si l'extension ne contient pas de *, elle est ajoutée à la fin du nom de fichier actuel en tant que suffixe. Si l'extension contient un ou plusieurs caractères *, chaque * est remplacé par le nom de fichier actuel.

Et rappelez-vous qu’aucun lien logiciel ou lien matériel n’est conservé:

Notez que, comme -i renomme ou supprime le fichier d'origine avant de créer un nouveau fichier du même nom, les liens logiciels et matériels de style UNIX ne seront pas conservés.

Enfin, le commutateur -i n'entrave pas l'exécution lorsqu'aucun fichier n'est donné sur la ligne de commande. Dans ce cas, aucune sauvegarde n'est effectuée (le fichier d'origine ne peut bien sûr pas être déterminé) et le traitement se déroule de STDIN vers STDOUT comme on pouvait s'y attendre.

Cela explique aussi pourquoi vous devez utiliser -iavec -poption ou utiliser une explicite printdéclaration si vous voulez modifier inplace avec 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
cuonglm
la source