Gnu sed 可以执行一个增加值的 bash 函数

Gnu sed 可以执行一个增加值的 bash 函数

gnu sed 如何执行 bash 函数将计数器值增加为

$ k(){ ((i++)); echo $i ;} ;export -f k
$ i=; echo -e 'oAo\nooAo\nAo' | sed -E '/A/e k'
1
oAo
1
ooAo
1
Ao

失败而不是正确地进行计数器

答案1

进程不能影响其父进程的环境。当您使用 sed 的 e命令时,它会分叉一个新的 shell 来运行该命令(它继承导出的k函数),并且对该 shell 的变量所做的任何更改i都会在它终止时丢失(即 k 函数退出时)。

如果你想增加一个变量,你必须将它存储在环境之外的某个地方。例如在一个文件中。如果您不想使用文件,则没有理由不能使用类似memcachedredis或 SQL 数据库之类的东西。

例如:

k() {
  local counterfile i
  counterfile='/tmp/counter.i'
  [ -e "$counterfile" ] && i=$(cat "$counterfile")
  ((i++))
  echo "$i" | tee "$counterfile"
}
export -f k

当您现在运行它时,计数器会递增:

$ rm /tmp/counter.i
$ printf 'oAo\nooAo\nAo' | sed -E '/A/e k'
1
oAo
2
ooAo
3
Ao
$ echo 100 > /tmp/counter.i
$ printf 'oAo\nooAo\nAo' | sed -E '/A/e k'
101
oAo
102
ooAo
103
Ao

顺便说一句,虽然 sed 的e命令很有用,但我认为 perl 对于您正在做的事情来说是一种更好的语言。例如

$ printf 'oAo\nooAo\nAo' |
    perl -lpe 'BEGIN { $i=shift || 0 };
               if (/A/) {print ++$i}' 10
11
oAo
12
ooAo
13
Ao

如果您不提供参数,则$i默认为零。

如果您希望脚本看起来更像“sed”,有很多方法可以$i在包含 的行上递增和打印计数器变量A。这是另一个:

/A/ && print ++$i

如果每行可能有多个匹配项,并且您需要在每个匹配项上递增并打印计数器,那么您需要迭代匹配项。例如

$ printf 'oAo\noAoAoAo\nAo' |
    perl -lpe 'BEGIN { $i=shift || 0 };
               for (/oA/g) {print ++$i}'
1
oAo
2
3
4
oAoAoAo
Ao

或者,如果您不需要累计总数,而只需要计算每行上的匹配项:

$ printf 'oAo\noAoAoAo\nAo' |
    perl -lne '$c = () = $_ =~ /oA/g;
               printf "%02i:%s\n", $c, $_'
01:oAo
03:oAoAoAo
00:Ao

最后一个可能需要一些解释。阅读它向后,该$c = () = $_ =~ /oA/g语句首先执行正则表达式匹配/oA/g,并将列表上下文中的结果返回到空列表(),然后将其分配给变量$c。因为$c是标量变量,而不是数组/列表,所以这是在标量上下文中计算的,因此返回该列表中的元素数量。这是一个相当常见的 Perl 习惯用法,用于计算匹配数。


注意:perl 的-p选项使其运行方式与 sed 非常相似(即迭代其输入并在处理后打印每一行,除非语句阻止打印)。 Perl 的-n选项使其运行起来很像sed -n(迭代输入,仅打印明确指示打印的内容)。

最后,值得注意的是,这个 sed 和 bash 函数版本会分叉bash, cat, 和tee对于每个匹配的输入行/A/。 Perl 版本不分叉任何内容,它只是迭代其输入。另外值得注意的是,您必须在 bash 中 fork 一个外部程序才能完成的许多事情可以通过 Perl 使用其自己的内置语法(或数千个库模块之一)在内部完成

答案2

当您使用 GNU sed 时,您无需求助于用户定义的函数即可获得所需的结果。这里我们利用保存空间来保存递增计数。

echo -e 'oAo\nooAoAoA\no' | 
sed -En "/A/!d
  p;:a
  H;g
  s/^(\n*).*/expr '\1' : '.*'/ep
  g;s//\1/;x;s/^\n*//;s/A//;//ba
"

输出:

oAo
1
ooAoAoA
2
3
4

相关内容