如何在 Bash 中没有 "memory issue" 的情况下每第 n 个定界符后插入 \n
How to insert \n after every nth delimiter without "memory issue" in Bash
我有一个以“Ç”作为分隔符的序列大文件。
我们需要在每 40 个“Ç”处拆分成一个新行。
我们已尝试使用 perl/cut 命令,但出现 "out of memory" 错误,因为它是一个巨大的文件并且 read/write一次发生。
所以我想要的是下面的
每出现 40 个定界符就剪切一次,write/flush 到文件中,不保存在内存中,然后对接下来的 40 个定界符再次执行相同操作,依此类推。
这在 Bash 中可以实现吗?
非常感谢任何帮助。
编辑:
这是我们在 PERL 中使用的命令
perl -pe 's{Ç}{++$n % 40 ? $& : "\n"}ge' <file_name>
说数据如下
123ÇasfiÇsadfÇtest1Ç123ÇasfiÇsadfÇtest1ÇmockÇdataÇtest1Ç123ÇasfiÇsadfÇtest1ÇmockÇdata
我想在(比如新行的第 3 个定界符)处剪切并分配给变量或其他内容并将其刷新到文件以便清除内存。
预期输出
123ÇasfiÇsadf
test1Ç123Çasfi
sadfÇtest1Çmock
注意:这是一个巨大的序列文件。
我们能够使用上面的命令实现所需的输出,但是对于更大的文件,它会抛出内存异常,因此我们想要刷新块。
如果 Python 是一个选项,这里是我建议的 C 代码的移植:
# -*- coding: latin1 -*-
import sys
def cvt(fdin, fdout, delim, count):
curr = count
while True:
c = fdin.read(1)
if c is None or c == '': break
if c == delim:
curr -= 1
if curr == 0:
curr = count
c = '\n'
dummy = fdout.write(c)
cvt(sys.stdin, sys.stdout, 'Ç', 3)
它给出了预期的结果:
echo "123ÇasfiÇsadfÇtest1Ç123ÇasfiÇsadfÇtest1ÇmockÇdataÇtest1Ç123ÇasfiÇsadfÇtest1ÇmockÇdata" | python ess.py
123ÇasfiÇsadf
test1Ç123Çasfi
sadfÇtest1Çmock
dataÇtest1Ç123
asfiÇsadfÇtest1
mockÇdata
有点长,但是告诉Perl把Ç
当作记录分隔符而不是\n
;然后你可以在阅读时加入 "lines",将它们分批处理,然后分组输出。 (我的 Perl 生锈了;可能有更简单的方法来做到这一点。)
perl -ne 'BEGIN {$/="Ç"; $c=0; sub d { chomp $out; print "$out\n"; $out=""; $c=0; }}
$out .= $_; $c++; &d if $c == 3;
END { &d }' tmp.txt
在脚本的开头,我们将 $/
从其默认值换行符更改为您的分隔符;现在 "line" 被定义为以 Ç 结尾的字符串。我们初始化一个计数器 $c
来跟踪我们读取了多少行,我们定义了一个子程序来输出在变量 $out
中累积的行,然后重置累加器和计数器。
对于每一行输入,我们首先将该行附加到累加器,递增计数器,然后在计数器的值达到我们的目标组大小时调用我们的输出例程。
最后,我们在输入末尾调用输出例程来刷新累加器中的所有剩余行。
我有一个以“Ç”作为分隔符的序列大文件。 我们需要在每 40 个“Ç”处拆分成一个新行。
我们已尝试使用 perl/cut 命令,但出现 "out of memory" 错误,因为它是一个巨大的文件并且 read/write一次发生。
所以我想要的是下面的
每出现 40 个定界符就剪切一次,write/flush 到文件中,不保存在内存中,然后对接下来的 40 个定界符再次执行相同操作,依此类推。
这在 Bash 中可以实现吗?
非常感谢任何帮助。
编辑:
这是我们在 PERL 中使用的命令
perl -pe 's{Ç}{++$n % 40 ? $& : "\n"}ge' <file_name>
说数据如下
123ÇasfiÇsadfÇtest1Ç123ÇasfiÇsadfÇtest1ÇmockÇdataÇtest1Ç123ÇasfiÇsadfÇtest1ÇmockÇdata
我想在(比如新行的第 3 个定界符)处剪切并分配给变量或其他内容并将其刷新到文件以便清除内存。
预期输出
123ÇasfiÇsadf
test1Ç123Çasfi
sadfÇtest1Çmock
注意:这是一个巨大的序列文件。 我们能够使用上面的命令实现所需的输出,但是对于更大的文件,它会抛出内存异常,因此我们想要刷新块。
如果 Python 是一个选项,这里是我建议的 C 代码的移植:
# -*- coding: latin1 -*-
import sys
def cvt(fdin, fdout, delim, count):
curr = count
while True:
c = fdin.read(1)
if c is None or c == '': break
if c == delim:
curr -= 1
if curr == 0:
curr = count
c = '\n'
dummy = fdout.write(c)
cvt(sys.stdin, sys.stdout, 'Ç', 3)
它给出了预期的结果:
echo "123ÇasfiÇsadfÇtest1Ç123ÇasfiÇsadfÇtest1ÇmockÇdataÇtest1Ç123ÇasfiÇsadfÇtest1ÇmockÇdata" | python ess.py
123ÇasfiÇsadf
test1Ç123Çasfi
sadfÇtest1Çmock
dataÇtest1Ç123
asfiÇsadfÇtest1
mockÇdata
有点长,但是告诉Perl把Ç
当作记录分隔符而不是\n
;然后你可以在阅读时加入 "lines",将它们分批处理,然后分组输出。 (我的 Perl 生锈了;可能有更简单的方法来做到这一点。)
perl -ne 'BEGIN {$/="Ç"; $c=0; sub d { chomp $out; print "$out\n"; $out=""; $c=0; }}
$out .= $_; $c++; &d if $c == 3;
END { &d }' tmp.txt
在脚本的开头,我们将 $/
从其默认值换行符更改为您的分隔符;现在 "line" 被定义为以 Ç 结尾的字符串。我们初始化一个计数器 $c
来跟踪我们读取了多少行,我们定义了一个子程序来输出在变量 $out
中累积的行,然后重置累加器和计数器。
对于每一行输入,我们首先将该行附加到累加器,递增计数器,然后在计数器的值达到我们的目标组大小时调用我们的输出例程。
最后,我们在输入末尾调用输出例程来刷新累加器中的所有剩余行。