Как заменить строки в файле и «сохранить» его как другой файл - PullRequest
3 голосов
/ 11 февраля 2012

Я пытаюсь заменить строку в куче * .txt файлов.Я знаком с этой командой:

find "$folder" -type f -name '*.txt' -exec sed -i 's/REPLACEFROM/REPLACETO/g' {} \;

Однако это (в соответствии с флагом -i) заменяет строки на месте.

Что я хотел бы сделать, это сохранить все исходные файлы без измененийи "сохранить" измененные файлы как "file1-renamed.txt", "file2-renamed.txt", ...

Какой самый быстрый и элегантный способ сделать это?Может быть, perl?

Я уверен, что это довольно просто, но мне кажется, это сложно.:)

Заранее благодарим за помощь.

Ответы [ 5 ]

3 голосов
/ 11 февраля 2012

С помощью sed вы можете использовать

 sed -i.back

. Таким образом, исходный файл будет перемещен в * .back

. Или используйте этот фрагмент кода как ближайший к вашему вопросу:

find "$folder" -type f -name '*.txt' -exec bash -c '
    cp "$1" "${1%.*}-renamed.txt"
    sed -i 's/REPLACEFROM/REPLACETO/g' "${1%.*}-renamed.txt"
' -- {} \;
2 голосов
/ 11 февраля 2012

С Perl вы можете попробовать что-то вроде этого:

find "$folder" -name '*.txt' |
  xargs perl -ne 'open NEW, ">>$ARGV.new"; s/from/to/g; print NEW'

Это сохранит новые файлы как old-name.txt.new. Возможно, вам придется изменить его, если вы действительно хотите формат "old-name-renamed.txt". Также обратите внимание, что он будет добавляться к новым файлам после каждого выполнения oneliner.

Конечно, было бы проще использовать опцию -i (... perl -i.old -pe 's/from/to/g') и затем переименовывать файлы в желаемый формат имени, поэтому это решение, вероятно, имеет смысл, только если исходные файлы недоступны для записи. *

0 голосов
/ 12 февраля 2012

Я уже разместил ответ здесь, но сегодня мне пришло в голову другое решение:

for f in (find "$folder" -name '*.txt'); do perl -ne 's/from/to/g' $f > "$f.new"; done

Опять же, он сохранит измененный контент в "old-name.txt.new" (вы можете изменить его на что-то вроде ... > "$(basename $f)-renamed.txt" ..., если хотите).

Этот ответ лучше моего предыдущего, поскольку он не требует открытия одного и того же файла для каждой новой строки.

0 голосов
/ 11 февраля 2012

Это может работать для вас:

find "$folder" -type f -name '*.txt' |
parallel sed 's/REPLACEFROM/REPLACETO/g' ">" {.}-renamed.txt
0 голосов
/ 11 февраля 2012

Это не совсем одна строка, но это должно сработать (и IMO легче читать):

use strict;
use warnings;

while(@ARGV)
{
  my $file=shift;
  open(my $read,"<",$file) or die $!;
  my $output_file=$file . "_renamed";
  if($file=~/^(.+)\.txt$/)
  {
    $output_file=$1 . "-renamed.txt";
  }

  open(my $write,">",$output_file) or die $!;

  while(<$read>)
  {
    chomp;
    s/REPLACEFROM/REPLACETO/g;
    print $write "$_\n";
  }
  close($read);
  close($write);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...