2009-05-21 2 views
0

У меня есть проект, в котором у меня есть папки, подпапки и файлы. Мне нужно заменить слово Masi словом Bond в каждом файле.Невозможно заменить слово в содержимом данной папки Sed/Python/Perl

я запускаю следующий Sed сценарий под названием заменить неудачно

s/Masi/Bond/ 

в Zsh по

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

Это дает мне все файлы, а также те, которые не имеют Мази, как выход.

Сед не обязательно является лучшим инструментом для выполнения задачи. Меня интересуют Python и Perl.

Как бы вы заменили Sed/Perl/Python, так, чтобы были изменены только содержимое файла?

+0

Вы хотите заменить строку в именах файлов или в содержимом файлов? – fmarc

+0

Что заставляет вас думать, что sed может переименовывать каталоги? Почему вы не используете «mv» или какую-либо другую команду, которая переименовывает файлы? –

+0

@fmarc: Я хочу заменить строку в содержимом файла, а не на имена файлов. –

ответ

12

Чтобы заменить слово во всех найденных файлов в текущем каталоге и подкаталогах

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

выше не будет работать, если у вас есть пробелы в имена файлов. Безопаснее сделать:

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

или в Mac, который имеет пробелы в именах файлов

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

Пояснения

  • -p означает печать или умереть
  • -i означает «не делать резервные файлы "
  • -e позволяет запускать perl c ода в командной строке
+1

+1 для отличного трюка grep только для изменения файлов, которые необходимо изменить. –

+3

+1 Ты меня избил. Это мой любимый perl один лайнер. Вопрос заключается в следующем: после использования этого одного лайнера для исправления сотен файлов за несколько секунд, продолжаете ли вы работать, или вы берете остаток дня, потому что, как долго это займет кто-то с блокнотом? –

+0

-i означает этот случай не имеет значения. Каковы другие варианты -p и -e? Я не нашел для них объяснений у человека perl. –

3

Почему бы просто не передать опцию -i (man sed) в sed и сделать с ней? Если он не найдет Masi в файле, файл будет просто перезаписан без каких-либо изменений. Или я чего-то не хватает?

Если вы не хотите, чтобы рядный заменить содержание файлов (который является то, что -i будет делать), вы можете сделать именно так, как вы сейчас, но бросить grep & xargs перед ним:

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

Множество вариантов, но сделать не написать полный скрипт perl для этого (я дам однострочный проход;)). find, grep, sed, xargs и т. Д. Всегда будет более гибким, ИМХО.

В ответ на комментарий:

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

@Sean: Как вы можете видеть, какие строки будут изменены до запуска команды? –

+0

Я обновил свой ответ, чтобы ответить на ваш комментарий. –

+0

@Sean: Ваше решение безопасно в критических средах, подобно http://stackoverflow.com/questions/894802/unable-to-replace-the-word-in-a-given-folders-contents-by-sed- python-perl/894982 # 894982? Я не уверен, насколько безопасно комбинировать команды. –

0

Раствор протестирована на Windows,

Требуется CPAN модуль File :: Slurp.Будет работать со стандартными шаблонами оболочки Unix. Как ./replace.pl PATH/replace.txt PATH2/заменить *

#!/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

Подстановочные знаки оболочки будут обрабатываться оболочкой. Обработка их в Perl не требуется. –

+2

Зависит от ОС :) - Я тестирую это на Windows. –

+1

Я с Александром здесь. Я никогда не видел, чтобы оболочка Windows открывала подстановочные знаки. – pjf

3

Переименование папки полной файлов:

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 ; 
} 

Замена строк в файлах

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 (ядро) - Perl-прагма для ограничения небезопасных конструкций
  • warnings (ядро) - Perl Прагма для управления Необязательные предупреждения
  • File::Find::Rule - альтернативный интерфейс File :: Find
  • File::Find (ядро) - траверс дерева каталогов.
  • File::Slurp - Эффективное чтение/запись файлов Complete
  • File::Copy (ядро) - копирование файлов или дескрипторы файлов
+0

Включает ли последний скрипт все файлы, включая подкаталоги? - - Хаос дал мне его похожий сценарий в http://lostsouls.org/grimoire_convert_all. Ваш скрипт кажется короче. Это говорит о том, что это не чистый Perl. Какие части вы улучшили бы в своем сценарии, чтобы сделать его безопасным в критических средах? –

+1

@ Маси, э-э, уверен, что его чистый перл, он просто использует модули для тяжелого подъема, и они выполняют всю тяжелую работу, которая была решена для меня. Файл :: Найти :: Правило совершенно безопасно для критических сред, возможно, * больше *, чем делать DIY с помощью ручного opendir, потому что его, по крайней мере, * проверенные * на * нескольких * платформах работают так, как ожидалось. –

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) 
Смежные вопросы