2017-09-17 5 views
0

J'essaie de modifier le contenu d'un fichier en utilisant Perl.Comment modifier le contenu d'un fichier en utilisant un seul fichier

Le script suivant fonctionne correctement.

#!/usr/bin/perl 

use strict; 
use warnings; 

open(FH,"test.txt") || die "not able to open test.txt $!"; 
open(FH2,">","test_new.txt")|| die "not able to opne test_new.txt $!"; 

while(my $line = <FH>) 
{ 
     $line =~ s/perl/python/i; 
     print FH2 $line; 
} 
close(FH); 
close(FH2); 

Le contenu de test.txt:

im learning perl 
im in File handlers chapter 

La sortie en test_new.txt:

im learning python 
im in File handlers chapter 

Si je tente d'utiliser le même fichier poignée pour modifier le contenu du fichier, alors je suis ne pas obtenir la sortie attendue. Ce qui suit est le script qui tente de le faire:

#!/usr/bin/perl 

use strict; 
use warnings; 

open(FH,"+<","test.txt") || die "not able to open test.txt $!"; 

while(my $line = <FH>) 
{ 
     $line =~ s/perl/python/i; 
     print FH $line; 
} 
close(FH); 

sortie incorrecte dans test.txt:

im learning perl 
im learning python 
chapter 
chapter 

Comment puis-je modifier le contenu du fichier à l'aide de descripteur de fichier unique?

+2

En pratique, vous aurez toujours envie d'écrire dans un autre fichier, même 'perl -i -pe 's/perl/python/i' test.txt' fonctionne de cette manière. Vous pouvez également lire le fichier entier à la fois, apporter des modifications et réécrire le fichier entier sur le même handle. –

+0

@ Сухой27 pouvez-vous expliquer ce que font les options dans la commande i.e -i -pe – kart1657

+1

C'est le fichier ** handle **, pas gestionnaire. – melpomene

Répondre

0

Comme @ Сухой27 a répondu

il est typique que la situation perl onliner utilisé plaisamment.

perl -i -pe 's/perl/python/i'

perl prend des options ci-dessous

  • -p: ligne marque par boucle de ligne (chaque ligne assigner en $_ et impression après évaluation $_)
  • -e: évaluation du bloc de code dans la boucle ci-dessus (regex prend $_ comme opérande par défaut)
  • -i: en modifier de fichier plcae (si vous passez des arguments pour -i, perl conserver les fichiers originaux avec cette extention)

si vous exécutez ci-dessous le script

perl -i.bak -pe 's/perl/python/i' tEST.TXT

vous obtiendrez modifié test.txt

im learning python 
im in File handlers chapter 

et obtenir des fichiers texte originaux nommés dans test.txt.bak

im learning perl 
im in File handlers chapter 
+1

Notez que cela utilise deux poignées. – ikegami

2

Vous ne pouvez pas supprimer d'un fichier (sauf à la fin).
Vous ne pouvez pas insérer de caractères dans un fichier (sauf à la fin).

Vous pouvez remplacer un caractère dans un fichier.
Vous pouvez ajouter à un fichier.
Vous pouvez raccourcir un fichier.
C'est tout.

Vous imaginez que vous pouvez simplement remplacer "Perl" par "Python" dans le fichier. Ceux-ci ne sont pas de la même longueur, il faudrait donc insérer des caractères dans le fichier, et vous ne pouvez pas le faire.

Vous pouvez effectivement insérer des caractères dans un fichier en chargeant le reste du fichier en mémoire et en l'écrivant deux caractères plus loin. Mais cela devient délicat pour les très gros fichiers. C'est aussi très lent puisque vous finissez par copier une partie (éventuellement très grande) du fichier chaque fois que vous voulez insérer des caractères.

L'autre problème avec les modifications sur place est que vous ne pouvez pas récupérer à partir d'une erreur. Si quelque chose se produit, il vous restera un fichier incomplet ou corrompu.

Si le fichier est petit et que vous acceptez de perdre les données en cas de problème, l'approche la plus simple consiste à charger le fichier entier en mémoire.

open(my $fh, '<+', $qfn) 
    or die("Can't open \"$qfn\": $!\n"); 

my $file = do { local $/; <$fh> }; 

$file =~ s/Perl/Python/g; 

seek($fh, 0, SEEK_SET) 
    or die $!; 
print($fh $file) 
    or die $!; 
truncate($fh) 
    or die $!; 

Une approche plus sûre consiste à écrire les données dans un nouveau fichier, puis renommez le fichier lorsque vous avez terminé.

my $new_qfn = $qfn . ".tmp"; 
open(my $fh_in, '<', $qfn) 
    or die("Can't open \"$qfn\": $!\n"); 
open(my $fh_out, '<', $new_qfn) 
    or die("Can't create \"$new_qfn\": $!\n"); 

while (<$fh_in>) { 
    s/Perl/Python/g; 
    print($fh_out $_); 
} 

close($fh_in); 
close($fh_out); 

rename($qfn_new, $qfn) 
    or die $!; 

L'inconvénient de cette approche est qu'il pourrait modifier les autorisations du fichier, et les liens physiques pointera vers l'ancien contenu à la place du nouveau fichier. Vous avez également besoin d'autorisations pour créer un fichier.