150 votes

Changer toutes les occurrences dans un dossier

J'ai besoin de faire une recherche regex et un remplacement sur tous les fichiers d'un dossier (et ses sous-dossiers). Quelle serait la commande shell Linux pour faire cela?

Par exemple, je veux exécuter ceci sur tous les fichiers et écraser l'ancien fichier avec le nouveau texte remplacé.

sed 's/texte ancien/nouveau texte/g'

0 votes

2voto

Foivos Points 390

Cela a fonctionné pour moi (sur le terminal de mac, sur Linux vous n'avez pas besoin de '' -e):

sed -i '' -e 's/ancien texte/nouveau texte/g' `grep 'ancien texte' -rl *`

la commande grep 'ancien texte' -rl * liste tous les fichiers du répertoire de travail (et des sous-répertoires) où "ancien texte" existe. Ceci est ensuite passé à sed.

0voto

Mark Points 648

Si vous êtes inquiet de supprimer des fichiers que vous n'avez pas pris en compte par erreur, vous pouvez exécuter grep avec l'option récursive d'abord pour voir quels fichiers seront potentiellement modifiés :

grep -r 'chaîne de recherche' *

Il n'est alors pas difficile de mettre en place quelque chose qui exécutera le remplacement sur chacun de ces fichiers :

for f in $(grep -r 'chaîne de recherche' *)
do
    sed -i -e 's/chaîne de recherche/remplacement/g' "$f"
done

(Valable uniquement avec GNU sed - des ajustements seraient nécessaires pour la compatibilité POSIX car l'option en place -i est une extension GNU) :

-1voto

chaos Points 69029

Peut-être vouloir essayer mon script Perl de recherche/remplacement de masse. A certains avantages par rapport aux solutions utilisant des utilitaires en chaîne (comme ne pas avoir à gérer plusieurs niveaux d'interprétation de métacaractères de shell).

#!/usr/bin/perl

use strict;

use Fcntl qw( :DEFAULT :flock :seek );
use File::Spec;
use IO::Handle;

die "Utilisation : $0 startdir search replace\n"
    unless scalar @ARGV == 3;
my $startdir = shift @ARGV || '.';
my $search = shift @ARGV or
    die "Le paramètre de recherche ne peut pas être vide.\n";
my $replace = shift @ARGV;
$search = qr/\Q$search\E/o;

my @stack;

sub process_file($) {
    my $file = shift;
    my $fh = new IO::Handle;
    sysopen $fh, $file, O_RDONLY or
        die "Impossible de lire $file : $!\n";
    my $found;
    while(my $line = <$fh>) {
        if($line =~ /$search/) {
            $found = 1;
            last;
        }
    }
    if($found) {
        print "  Traitement dans $file\n";
        seek $fh, 0, SEEK_SET;
        my @file = <$fh>;
        foreach my $line (@file) {
            $line =~ s/$search/$replace/g;
        }
        close $fh;
        sysopen $fh, $file, O_WRONLY | O_TRUNC or
            die "Impossible d'écrire dans $file : $!\n";
        print $fh @file;
    }
    close $fh;
}

sub process_dir($) {
    my $dir = shift;
    my $dh = new IO::Handle;
    print "Entrée dans $dir\n";
    opendir $dh, $dir or
        die "Impossible d'ouvrir $dir : $!\n";
    while(defined(my $cont = readdir($dh))) {
        next
            if $cont eq '.' || $cont eq '..';
        # Ignorer les fichiers .swap
        next
            if $cont =~ /^\.swap\./o;
        my $fullpath = File::Spec->catfile($dir, $cont);
        if($cont =~ /$search/) {
            my $newcont = $cont;
            $newcont =~ s/$search/$replace/g;
            print "  Renommer $cont en $newcont\n";
            rename $fullpath, File::Spec->catfile($dir, $newcont);
            $cont = $newcont;
            $fullpath = File::Spec->catfile($dir, $cont);
        }
        if(-l $fullpath) {
            my $link = readlink($fullpath);
            if($link =~ /$search/) {
                my $newlink = $link;
                $newlink =~ s/$search/$replace/g;
                print "  Recréer le lien symbolique $cont de $link à $newlink\n";
                unlink $fullpath;
                my $res = symlink($newlink, $fullpath);
                warn "Lien symbolique de $newlink vers $fullpath a échoué\n"
                    unless $res;
            }
        }
        next
            unless -r $fullpath && -w $fullpath;
        if(-d $fullpath) {
            push @stack, $fullpath;
        } elsif(-f $fullpath) {
            process_file($fullpath);
        }
    }
    closedir($dh);
}

if(-f $startdir) {
    process_file($startdir);
} elsif(-d $startdir) {
    @stack = ($startdir);
    while(scalar(@stack)) {
        process_dir(shift(@stack));
    }
} else {
    die "$startdir n'est ni un fichier ni un répertoire\n";
}

-1voto

DimiDak Points 515
pour i in $(ls);faire sed -i 's/old_text/new_text/g' $i;terminer

-2voto

tereza Points 27

Si le nom des fichiers dans le dossier a des noms réguliers (comme fichier1, fichier2...), j'ai utilisé une boucle for.

for i in {1..10000..100}; do sed 'old\new\g' 'fichier'$i.xml > 'cfichier'$i.xml; done

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X