web-dev-qa-db-fra.com

En Perl, comment puis-je modifier, supprimer ou insérer une ligne dans un fichier ou l'ajouter au début d'un fichier?

Je souhaite apporter des modifications au contenu d'un fichier en modifiant, supprimant ou insérant des lignes ou en ajoutant au début du fichier. Comment faire ça en Perl?


Il s'agit d'une question de la FAQ officielle . Nous sommes importation du perlfaq dans Stack Overflow .

27
perlfaq

(Ceci est le réponse perlfaq officielle , moins les modifications ultérieures)

L'idée de base d'insérer, de modifier ou de supprimer une ligne d'un fichier texte implique la lecture et l'impression du fichier au point où vous souhaitez apporter la modification, la modification, puis la lecture et l'impression du 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 :: File puissent le simuler.

Un programme Perl pour effectuer ces tâches prend la forme de base d'ouvrir un fichier, d'imprimer ses lignes, puis de fermer 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 ce formulaire de base, ajoutez les pièces dont vous avez besoin pour insérer, modifier ou supprimer des lignes.

Pour ajouter des lignes au début, imprimez ces lignes avant d'entrer dans 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 while. Dans ce cas, le code trouve toutes les versions en minuscules de "Perl" et les met en majuscules. Cela se produit pour chaque ligne, alors assurez-vous que vous êtes censé le faire sur chaque ligne!

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 modifier uniquement une ligne particulière, le numéro de ligne d'entrée, $., Est utile. Lisez d'abord et imprimez les lignes jusqu'à celle que vous souhaitez modifier. Ensuite, lisez la seule ligne que vous souhaitez modifier, modifiez-la et imprimez-la. Après cela, lisez le reste des lignes et imprimez-les:

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 ignore les lignes de commentaire, et le dernier arrête tout traitement une fois qu'il 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 à côté de sauter les lignes que vous ne souhaitez pas afficher dans la sortie. Cet exemple saute toutes les cinq lignes:

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

Si, pour une raison étrange, vous voulez vraiment voir le fichier entier à la fois plutôt que de le traiter ligne par ligne, vous pouvez le slurper (tant que vous pouvez tenir le 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 File :: Slurp et Tie :: File peuvent également vous aider. Si vous le pouvez, cependant, évitez de lire tout le fichier en même temps. Perl ne restituera pas cette mémoire au système d'exploitation avant la fin du processus.

Vous pouvez également utiliser des monolignes Perl pour modifier un fichier sur place. Ce qui suit change tout "Fred" en "Barney" dans inFile.txt, écrasant le fichier avec le nouveau contenu. Avec le -p switch, Perl encapsule une boucle while autour du 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 effectuer une sauvegarde de inFile.txt, donnez à -i une extension de fichier à ajouter:

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

Pour modifier uniquement la cinquième ligne, vous pouvez ajouter une vérification de test $., le numéro de la ligne d'entrée, puis effectuez l'opération uniquement lorsque le test réussit:

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 s'imprime à 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 déjà dans le fichier, utilisez le -n commutateur. C'est comme -p sauf qu'il n'imprime pas $_ à la fin de la boucle, vous devez donc le faire vous-même. Dans ce cas, imprimez $_ 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 celles que vous souhaitez.

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