逐行应用字符串替换

时间:2019-05-16 15:49:01

标签: bash sed text-processing string-substitution

我需要使用具有相同行数的过滤器文件对文本文件进行一系列替换:过滤器的n行应应用于原始文件的n行。

例如原始文件:

foo
bar
foobar

过滤文件:

s/oo/uu/
s/a/i/
s/b/l/

预期结果:

fuu
bir
foolar

由于sed将在每行上应用每个过滤器,因此使用sed -f filterfile的效率特别低(行数相当大,因此也相当大……)。此外,尽管在我的特殊情况下,我可以修改过滤器来避免此问题,但是此命令将导致示例错误的结果。

我目前正在实施以下方法(仍在尝试解决列表问题...):

paste -d'@' filterA filterB infile \
  |while IFS="@" read AA BB LINE;
do
  echo $LINE|"s/$AA/$BB/g"
done > outfile

但是我想知道是否有更优雅的解决方案,例如一些sed选项? (最好使用标准的GNU / Linux工具。)

2 个答案:

答案 0 :(得分:3)

您可以通过在每行前面添加适当的行地址来修改过滤器文件

$ nl filter
     1  s/oo/uu/
     2  s/a/i/
     3  s/b/l/

然后将其通过管道传递到sed:

$ nl filter | sed -f- infile
fuu
bir
foolar

如果需要全局替换,请先附加g

$ sed 's/$/g/' filter
s/oo/uu/g
s/a/i/g
s/b/l/g

导致

sed 's/$/g/' filter | nl | sed -f- infile

替换后开始下一个循环的一个小的优化是在其后添加一个b命令:

sed 's/.*/{&g;b}/' filter | nl | sed -f- infile

这将立即开始下一个循环。对于该问题,输入和过滤器文件的30,000行版本的效果大约可节省20%的时间:

$ wc -l filter infile
 33033 filter
 33033 infile
 66066 total
$ time sed 's/$/g/' filter | nl | sed -f- infile >/dev/null

real    0m15.868s
user    0m15.522s
sys     0m0.296s
$ time sed 's/.*/{&g;b}/' filter | nl | sed -f- infile >/dev/null

real    0m12.238s
user    0m11.901s
sys     0m0.271s

如果文件很大,awk会快得多(代码由Ed Morton提供):

$ time awk 'NR==FNR{o[NR]=$2;n[NR]=$3;next} {gsub(o[FNR],n[FNR])} 1' filter infile >/dev/null

real    0m0.073s
user    0m0.061s
sys     0m0.007s

答案 1 :(得分:2)

(function(i, s, o, g, r, a, m) {
  i['GoogleAnalyticsObject'] = r;
  i[r] = i[r] || function() {
    (i[r].q = i[r].q || []).push(arguments)
  }, i[r].l = 1 * new Date();
  a = s.createElement(o),
    m = s.getElementsByTagName(o)[0];
  a.async = 1;
  a.src = g;
  m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');

ga('create', 'UA-44871699-2', 'auto');
ga('require', 'displayfeatures');

//updated to track page query string and hash
ga('send', 'pageview', {
  'page': location.pathname + location.search + location.hash
});

//Function for tracking links
function trackOutboundLinks(category, action, label, url) {
  ga('send', 'event', category, action, label)
}
//Testing it with the below event
var $cart = $('#cart-checkout')

$cart.on('click', function() {
  console.log('clicked');
  trackOutboundLinks("cart", "click", "logo", $(this).attr("href"));
});

以上内容可在任何UNIX盒中的任何shell中使用任何awk进行工作。