web-dev-qa-db-fra.com

Comment remplacer les lignes au milieu d'un fichier avec Perl?

J'ouvre le fichier en mode APPEND. Je dois remplacer les lignes 2,3 et 4 dans le fichier, puis j'ai besoin d'ajouter les nouvelles données à la fin du fichier.

19
kkchaitu

Je pense que c'est le FAQ réponse que j'ai republié à Stackoverflow le plus. Le perlfaq5 a la réponse à Comment puis-je changer, supprimer, Ou insérez une ligne dans un fichier ou annoncez au début d'un fichier? .

Oubliez les trucs de mode append. Cela va juste rendre votre vie plus difficile.


L'idée de base de l'insertion, de la modification ou de la suppression d'une ligne d'un fichier texte implique la lecture et l'impression du fichier au point que vous souhaitez modifier, en effectuant la modification, puis en lisant et imprimez le reste du fichier. Perl ne fournit pas d'accès aléatoire aux lignes (en particulier depuis le séparateur d'entrée d'enregistrement, $/, est mutable), bien que des modules tels que - TIE :: Fichier peut simuler.

Un programme PERL pour effectuer ces tâches prend la forme de base d'ouverture d'un fichier, imprimer ses lignes, puis fermez le fichier:

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

while( <$in> )
    {
    print $out $_;
    }

close $out;

Dans cette forme de base, ajoutez les pièces dont vous avez besoin pour insérer, modifier ou supprimer des lignes.

Pour préparer des lignes au début, imprimez ces lignes avant de saisir la boucle qui imprime les lignes existantes.

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

print $out "# Add this line to the top\n"; # <--- HERE'S THE MAGIC

while( <$in> )
    {
    print $out $_;
    }

close $out;

Pour modifier les lignes existantes, insérez le code pour modifier les lignes à l'intérieur de la boucle. Dans ce cas, le code trouve toutes les versions de "Perl" et les majuscules. L'arrive pour chaque ligne, alors assurez-vous que vous êtes censé faire cela sur toutes les lignes!

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

print $out "# Add this line to the top\n";

while( <$in> )
    {
    s/\b(Perl)\b/Perl/g;
    print $out $_;
    }

close $out;

Pour ne changer qu'une ligne particulière, le numéro de ligne d'entrée, $. , est utile. D'abord lire et imprimer les lignes jusqu'à celui que vous souhaitez modifier. Ensuite, lisez la ligne unique que vous souhaitez modifier, le changer et l'imprimer. Après cela, lisez le reste des lignes et imprimez ceux-ci:

while( <$in> )   # print the lines before the change
    {
    print $out $_;
    last if $. == 4; # line number before change
    }

my $line = <$in>;
$line =~ s/\b(Perl)\b/Perl/g;
print $out $line;

while( <$in> )   # print the rest of the lines
    {
    print $out $_;
    }

Pour sauter des lignes, utilisez les commandes de bouclage. Le suivant dans cet exemple passe des lignes de commentaire et la dernière cesse de tout traitement une fois qu'elle rencontre soit __END__ ou __DATA__.

while( <$in> )
    {
    next if /^\s+#/;             # skip comment lines
    last if /^__(END|DATA)__$/;  # stop at end of code marker
    print $out $_;
    }

Faites le même genre de chose pour supprimer une ligne particulière en utilisant Suivant pour sauter les lignes que vous ne souhaitez pas apparaître dans la sortie. Cet exemple saute toutes les cinquième ligne:

while( <$in> )
    {
    next unless $. % 5;
    print $out $_;
    }

Si, pour une raison quelconque, vous voulez vraiment voir le fichier entier à la fois plutôt que de traiter la ligne de ligne, vous pouvez le réduire (aussi longtemps que vous pouvez vous adapter au tout en mémoire!):

open my $in,  '<',  $file      or die "Can't read old file: $!"
open my $out, '>', "$file.new" or die "Can't write new file: $!";

my @lines = do { local $/; <$in> }; # Slurp!

    # do your magic here

print $out @lines;

Des modules tels que Fichier :: slurp et Cravate :: Fichier peut aider à cela aussi. Si vous le pouvez, évitez toutefois de lire l'ensemble du fichier à la fois. Perl ne donnera pas cette mémoire au système d'exploitation jusqu'à ce que le processus finisse.

Vous pouvez également utiliser Perl One-Linders pour modifier un fichier en place. Les modifications suivantes changent 'Fred' à 'barney' dans infile.txt , écraser le fichier avec le nouveau contenu. Avec le -p Commutateur, Perl enveloppe une boucle tandis que sur le code que vous spécifiez avec -e, et -i active l'édition sur place. La ligne actuelle est en $_. Avec -p, Perl imprime automatiquement la valeur de $_ À la fin de la boucle. Voir Perlrun pour plus de détails.

Perl -pi -e 's/Fred/Barney/' inFile.txt

Pour faire une sauvegarde d'infile.txt, donnez -i une extension de fichier à ajouter:

Perl -pi.bak -e 's/Fred/Barney/' inFile.txt

Pour ne changer que la cinquième ligne, vous pouvez ajouter un test de test $., le numéro de ligne d'entrée, puis effectuer uniquement l'opération lorsque le test passe:

Perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt

Pour ajouter des lignes avant une certaine ligne, vous pouvez ajouter une ligne (ou des lignes!) Avant que Perl imprime $_:

Perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt

Vous pouvez même ajouter une ligne au début d'un fichier, car la ligne actuelle est imprimée à la fin de la boucle:

Perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt

Pour insérer une ligne après une heure déjà dans le fichier, utilisez le -n changer. C'est juste comme -p Sauf que cela n'imprime pas $_ À la fin de la boucle, vous devez donc le faire vous-même. Dans ce cas, impression $_ Tout d'abord, puis imprimez la ligne que vous souhaitez ajouter.

Perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt

Pour supprimer des lignes, imprimez uniquement ceux que vous souhaitez.

Perl -ni -e 'print unless /d/' inFile.txt

    ... or ...

Perl -pi -e 'next unless /d/' inFile.txt
40
brian d foy

Vous pouvez le faire avec Cravate :: Fichier . (Sachez qu'il devra réécrire l'intégralité du fichier afin de remplacer les lignes initiales, mais la naissance :: Fichier cachera les détails de votre part.)

4
cjm

Un bon idiome Perl est de lire et d'écrire l'entrée et la sortie standard. Vous pouvez tuyer et rediriger si nécessaire. À travers l'opérateur <> (une enveloppe à readline), Perl ouvrira les fichiers que vous transmettez comme argument sur la ligne de commande.

Pour répondre à votre question, quelques lignes de code (aussi propres que possible):

#!/usr/bin/env Perl
use strict; use warnings;

while (<>) {
  if ($. == 2) {
    print "new data", "\n";
    next;
  }
  if ($. == 3) {
    print "very new data", "\n";
    next;
  }
  print;
}

print "more data", "\n"; 

Ensuite, appelez-la de cette façon: Perl YourScript.pl entrementfile> OutputFileFile

Si vous souhaitez ouvrir les fichiers vous-même (ici, nous ignorons simplement les lignes indésirables):

my open $in_fh, '<', $inputfile
  or die "Can't open file $inputfile: $!";

my open $out_fh, '>', $outputfile
  or die "Can't open file $output: $!";

while (my $line = <$in_fh>) {
  next if ( $. == 2 or $. == 3 or $. == 4 );
  print $out_fh $line;
}
print $out_fh "...whatever\n";
3
i-blis

Si vous ouvrez un fichier dans APPEND MODE Ensuite, vous ne pouvez pas remplacer une ligne déjà dans le fichier lorsque vous l'avez ouverte. APPEND Fichier signifie que votre programme n'a la possibilité de lire le fichier et d'ajouter à la fin de celui-ci.

Vous pouvez créer un nouveau fichier, ajouter du contenu à celui-ci (peut-être sur la base du contenu d'un fichier différent), puis copiez le nouveau fichier sur le fichier différent.

Je suppose que je ne comprends pas bien l'affectation.

0
Larry K