Замена с использованием sed не работает должным образом

Вы можете сделать это, используяyum:

sudo yum remove exim4

2
15.10.2019, 22:49
3 ответа

Вместо того, чтобы перезаписывать выходной файл в каждой итерации цикла, вы можете копировать входной файл как выходной файл и работать с этим выходным файлом.

С параметром sedи -iизменения записываются в место -того же файла, поэтому предыдущие замены не теряются:

cp input output
while read bef aft
do
  echo "Searching for $bef"
  echo "Replacing with $aft"
  sed -i "s/$bef/$aft/g" output
done < template
1
27.01.2020, 22:02

Ваша проблема заключается в том, что вы затираете выходной файл на каждой итерации цикла, оставляя только самые последние изменения в outputи ни одно из более ранних.

Вместо этого вы можете легко преобразовать файл templateв набор команд sed:

$ awk '{ printf("s/%s/%s/g\n", $1, $2) }' template
s/MSTRG.1/AT1G01030/g
s/MSTRG.2/AT1G01010/g
s/MSTRG.3/AT1G01035/g

... а затем примените их к своему файлу:

$ awk '{ printf("s/%s/%s/g\n", $1, $2) }' template | sed -f - input
gene_id "AT1G01030";
gene_id "AT1G01030";
gene_id "AT1G01010";
gene_id "AT1G01035";

Некоторые реализации sedне распознают -как стандартный ввод. Чтобы использовать этот подход с таким sed, замените -f -на -f /dev/stdin.

Или вы можете просто сделать все это вawk:

$ awk 'FNR == NR { pat[$1] = $2; next } { for (p in pat) gsub(p, pat[p]); print }' template input
gene_id "AT1G01030";
gene_id "AT1G01030";
gene_id "AT1G01010";
gene_id "AT1G01035";

Обратите внимание, что во всех приведенных выше вариантах используется то, что находится в первом столбце templateв качестве регулярного выражения , что означает, что.(точка )будет соответствовать любому персонаж.

2
27.01.2020, 22:02
#!/usr/bin/perl -i

use strict;

# The %re hash holds the regexp searches and replacement strings.
my %re = ();

my $tfile = shift;
open(TEMPLATE, "<", $tfile) || die "couldn't open $tfile for read: $!\n";
while(<TEMPLATE>) {
   chomp;
   my ($search,$replace) = split;
   $re{qr/$search/} = $replace;
};
close(TEMPLATE);

while (<>) {
  foreach my $s (keys %re) {
    s/$s/$re{$s}/g;
  };
  print;
}

Это читает файл templateи создает ассоциативный массив (, также известный как "хеш" ), называемый %reпоиском и заменой регулярных выражений.

Затем он перебирает все оставшиеся имена файлов в командной строке (, например.input)и выполняет все эти операции поиска и замены для каждой строки ввода. Он использует qr//для предварительной -компиляции регулярных выражений -это всего лишь тривиальная оптимизация, если в templateне так много строк, но может привести к очень значительному ускорению, если строк много.

-iв строке #!/usr/bin/perl -iзаставляет Perl вносить изменения в -поместить во входные файлы, а не просто выводить изменения на стандартный вывод. Измените это, например, на -i.bak, если вы хотите, чтобы сохранялась резервная копия файлов до того, как они были изменены.

Сохранить как, например, cryptic0.pl, сделать его исполняемым с помощью chmod +x cryptic0.plи запустить так:

$./cryptic0.pl template input

Сценарий не будет выводить данные на терминал. Вместо этого он отредактирует входной файл (с ).

Например, ваш файл inputбудет изменен на:

$ cat input
gene_id "AT1G01030";
gene_id "AT1G01030";
gene_id "AT1G01010";
gene_id "AT1G01035";

Кстати, этот сценарий изменит все совпадения во всех строках на соответствующую строку замены. Если вы уверены, что в любой данной строке может быть только одно совпадение, вы можете ускорить его, изменив эту строку:

s/$s/$re{$s}/g;

к этому:

s/$s/$re{$s}/ && last;

Это приводит к тому, что сценарий переходит из цикла foreach к оператору print, а затем переходит к следующей строке ввода, как только он успешно выполнил поиск и замену.


Кстати, см. Почему использование цикла оболочки для обработки текста считается плохой практикой? почему не рекомендуется выполнять обработку текста с помощью циклов sh. Используйте awkили perlили sedили что-то другое вместо shили bash.

1
27.01.2020, 22:02

Теги

Похожие вопросы