如何在BASH中使用一次更换快速更换许多匹配项目?

时间:2013-04-19 23:25:32

标签: bash optimization replace

我有一个文件“items.txt”,其中包含我需要从文件“text.txt”中删除的100,000个项目的列表,并替换为“111111111”。

我写了这个脚本,它完全符合我的意图:

#!/bin/bash
a=0
b=`wc -l < ./items.txt`
while read -r line
do
    a=`expr $a + 1`
    sed -i "s/$line/111111111/g" text.txt
    echo "Removed ("$a"/"$b")."
done < ./items.txt

此脚本查看“items.txt”中的eat行,然后使用sed从“text.txt”中删除每一行。

但这个脚本非常慢。据我估计,从我的计算机上删除文件中的所有项目需要1周以上的时间。有没有更快捷的方法来快速更换所有项目?

BASH 4.1.5

3 个答案:

答案 0 :(得分:2)

使用sed构建一个sed脚本来替换所有项目:

sed 's/^/s=/;s/$/=111111111=g/' items.txt | sed -f- text.txt

更新:以下Perl脚本似乎更快:

#!/usr/bin/perl
use warnings;
use strict;

open my $ITEMS, '<', 'items.txt';
my @items = <$ITEMS>;
chomp @items;
my $regex = join '|', @items;
$regex    = qr/$regex/;

open my $TEXT, '<', 'text.txt';
while (<$TEXT>) {
    s/$regex/111111111/g;
    print;
}

答案 1 :(得分:1)

输出会减慢您的脚本速度。删除它,你会发现一个显着的加速。 要删除的行:

 echo "Removed ("$a"/"$b")."

答案 2 :(得分:1)

你的脚本很慢,不仅仅是因为输出(echo "Removed ("$a"/"$b").")。

主要原因是,您有

 sed -i "s/$line/111111111/g" text.txt

在while循环中。例如,您的items.txt有10k行,sed行将执行10k次。也就是说,阅读text.txt到10k次。如果text.txt也是10k,则为10k * 10k

你可以做得更好的是,只读一次这两个文件:

awk 'NR==FNR{a[$0];next}$0 in a{$0="1111111"}1' items.txt text.txt

我没有测试,但它应该可以工作。