2009-05-21 10 views
0

J'ai un projet dans lequel j'ai des dossiers, des sous-dossiers et des fichiers. J'ai besoin de remplacer le mot Masi par le mot Bond dans chaque fichier.Impossible de remplacer le mot dans le contenu d'un dossier donné par Sed/Python/Perl

je lance le script Sed suivant appelé sans succès remplacer

s/Masi/Bond/ 

à zsh par

sed -f PATH/replace PATH2/project/** 

Il me donne tous les fichiers, aussi ceux qui n'ont pas Masi, en tant que sortie.

Sed n'est pas nécessairement le meilleur outil pour la tâche. Je suis intéressé par Python et Perl.

Comment faire le remplacement dans Sed/Perl/Python, de sorte que seul le contenu du fichier est modifié?

+0

Voulez-vous remplacer la chaîne dans les noms de fichiers ou le contenu du fichier? – fmarc

+0

Qu'est-ce qui vous fait penser que sed peut renommer les répertoires? Pourquoi n'utilisez-vous pas "mv" ou une autre commande qui renomme les fichiers? –

+0

@fmarc: Je veux remplacer la chaîne dans le contenu du fichier, pas dans les noms de fichiers. –

Répondre

12

Pour remplacer le mot dans tous les fichiers trouvés dans le répertoire courant et des sous-répertoires

perl -p -i -e 's/Masi/Bond/g' $(grep -rl Masi *) 

ci-dessus ne fonctionnera pas si vous avez des espaces dans noms de fichiers. Plus sûr de le faire:

find . -type f -exec perl -p -i -e 's/Masi/Bond/g' {} \; 

ou Mac qui a des espaces dans les noms de fichiers

find . -type f -print0 | xargs -0 perl -p -i -e 's/Masi/Bond/g' 

Explications

  • -p signifie impression ou mourir
  • -i signifie « ne pas faire des fichiers de sauvegarde "
  • -e vous permet d'exécuter perl c ode en ligne de commande
+1

+1 pour un excellent truc grep pour ne modifier que les fichiers à modifier. –

+3

+1 Tu m'as battu dessus. C'est mon perl un paquebot préféré. La question est la suivante: après avoir utilisé ce liner pour réparer des centaines de fichiers en quelques secondes, continuez-vous à travailler, ou prenez-vous le reste de la journée parce que cela prend combien de temps quelqu'un avec un bloc-notes? –

+0

-i signifie que ce cas n'a pas d'importance. Quelles sont les autres options -p et -e? Je n'ai pas trouvé d'explications pour eux au man perl. –

3

Pourquoi ne pas simplement passer l'option -i (man sed) à sed et en avoir fini avec elle? S'il ne trouve pas Masi dans un fichier, le fichier sera simplement réécrit sans modification. Ou est-ce que je manque quelque chose?

Si vous ne souhaitez pas remplacer les contenus de fichiers en ligne (ce qui est ce que le -i fera), vous pouvez le faire exactement comme vous êtes maintenant, mais jetez un devant grep & xargs de celui-ci:

grep -rl Masi PATH/project/* | xargs sed -f PATH/replace 

Beaucoup d'options, mais ne pas écrire un script perl entier pour cela (je vais donner un one-liner une passe;)). find, grep, sed, xargs, etc sera toujours plus flexible, à mon humble avis.

En réponse au commentaire:

grep -rl Masi PATH/project/* | xargs sed -n -e '/Masi/ p' 
+0

@Sean: Comment pouvez-vous voir quelles lignes vont être modifiées avant d'exécuter la commande? –

+0

J'ai mis à jour ma réponse pour répondre à votre commentaire. –

+0

@Sean: Votre solution est-elle sûre dans les environnements critiques, de la même manière que http://stackoverflow.com/questions/894802/unable-to-replace-the-word-in-a-given-folders-contents-by-sed- python-perl/894982 # 894982? Je ne suis pas sûr de la sécurité de combiner les commandes. –

0

Une solution testée sur Windows

Nécessite module CPAN File :: Slurp.Fonctionne avec les caractères génériques de shell Unix standard. Comme ./replace.pl PATH/replace.txt CHEMIN2/remplacer *

#!/usr/bin/perl 

use strict; 
use warnings; 
use File::Glob ':glob'; 
use File::Slurp; 
foreach my $dir (@ARGV) { 
    my @filelist = bsd_glob($dir); 
    foreach my $file (@filelist) { 
    next if -d $file; 
    my $c=read_file($file); 
    if ($c=~s/Masi/Bond/g) { 
     print "replaced in $file\n"; 
     write_file($file,$c); 
    } else { 
     print "no match in $file\n"; 
    } 
    } 
} 
+0

Les caractères génériques du shell seront gérés par le shell. Les manipuler en Perl est inutile. –

+2

Selon OS :) - Je suis en train de tester cela sur Windows. –

+1

Je suis avec Alexandr ici. Je n'ai jamais vu le shell Windows faire une expansion générique. – pjf

3

Renommer un dossier complet de fichiers:

use warnings; 
use strict; 
use File::Find::Rule; 

my @list = File::Find::Rule->new()->name(qr/Masi/)->file->in('./'); 

for(@list){ 
    my $old = $_; 
    my $new = $_; 
    $new =~ s/Masi/Bond/g; 
    rename $old , $new ; 
} 

Remplacement des chaînes dans les fichiers

use warnings; 
use strict; 
use File::Find::Rule; 
use File::Slurp; 
use File::Copy; 

my @list = File::Find::Rule->new()->name("*.something")->file->grep(qr/Masi/)->in('./'); 

for(@list){ 
    my $c = read_file($_); 
    if ($c =~ s/Masi/Bond/g;){ 
    File::Copy::copy($_, "$_.bak"); # backup. 
    write_file($_ , $c); 
    } 
} 
  • strict (core) - Perl pragma pour limiter les constructions dangereuses
  • warnings (noyau) - Perl pragma pour contrôler les avertissements en option
  • File::Find::Rule - Interface alternative au fichier :: Trouver
  • File::Find (noyau) - Traverse une arborescence.
  • File::Slurp - Lecture efficace/écriture des dossiers complets
  • File::Copy (noyau) - Copiez les fichiers ou les handles de fichiers
+0

Est-ce que le dernier script renommer tous les fichiers, y compris les sous-répertoires? - - Chaos m'a donné son script similaire sur http://lostsouls.org/grimoire_convert_all. Votre script semble être plus court. Cela me suggère que ce n'est pas pur Perl. Quelles parties amélioreriez-vous dans votre script pour le rendre sûr dans les environnements critiques? –

+1

@Masi, euh, sûr de son perl pur, il utilise juste des modules pour faire le gros travail et ils font tout le dur labeur qui a été résolu pour moi. File :: Find :: Rule est parfaitement sûr pour les environnements critiques, peut-être * plus * que DIYing avec opendir manuel car il est au moins * testé * sur * plusieurs * plates-formes pour fonctionner comme prévu. –

0
import glob 
import os 

# Change the glob for different filename matching 
for filename in glob.glob("*"): 
    dst=filename.replace("Masi","Bond") 
    os.rename(filename, dst) 
Questions connexes