Bash while循环+切慢

Bash while loop + cut slow

我正在尝试使用 bash 循环来处理文件 (1.5GB) 以迭代每一行。我使用 cut 是为了它的简单性(相对),结果是:

while read line
do
    echo "$(echo $line | cut -d' ' -f 2-3)" "$(echo $line | cut -d'"' -f 20)"
done < TEST.log > IDS.log

这非常慢,大约只有 2KB/秒。我需要一些东西 运行 快很多。

还有,这里的瓶颈是什么?

瓶颈可能是您为每一行数据生成了多个进程。至于替换,这个awk应该是等价的:

awk '{ split([=10=], a, "\""); print , , a[20] }' TEST.log > IDS.log

Perl 通常非常快:

perl -nE 'say join " ", (split " ")[1,2], (split /"/)[19]' TEST.log > IDS.log

Perl 数组的索引从 0 开始。

这里最大的瓶颈是分离管道的子流程。只需摆脱命令替换和管道,您就可以获得实质性的(阅读:数量级)性能改进。

while IFS=$'\x01' read -r ss1 ss2 ss3 _ <&3 && \
      IFS='"' read -r -a quote_separated_fields; do
    printf '%s\n' "${ss2} ${ss3} ${quote_separated_fields[20]}"
done < TEST.log 3< <(tr ' ' $'\x01' <TEST.log) > IDS.log

这是如何工作的?

  • tr ' ' $'\x01' 将输入中的空格更改为低位 ASCII 字符以避免特殊情况处理(其中 read 会将空格合并为单个字符)。将此放在 3< <(...) 之后会将此操作的输出放在文件描述符 #3 上。
  • IFS=$'\x01' read -r ss1 ss2 ss3 _ <&3 在这些字符上拆分一行,将第一个字段放入 ss1(我们不关心),第二个放入 ss2,第三个放入 ss3,该行的剩余部分变为 _<&3 导致此行从文件描述符 3.
  • 读取
  • IFS='"' read -r -a quote_separated_fields" 个字符的标准输入 (FD 0) 上的输入拆分为一个名为 quote_separated_fields.
  • 的数组