在Linux上用1行2GB文件替换第一个字符串匹配

1 regex bash perl sed substitution

我试图仅在一个只有一行(2.1 GB)的巨大文件中替换一个字符串的第一个匹配项,这种替换将在shell脚本作业中进行.最大的问题是运行此脚本的机器只有1GB内存(大约300MB可用),所以我需要一个不会溢出内存的缓冲策略.我已经尝试了sed,perl并且采用了一种python方法,但是所有这些都让我失去了记忆错误.以下是我的尝试(在其他问题中发现):

# With perl
perl -pi -e '!$x && s/FROM_STRING/TO_STRING/ && ($x=1)' file.txt

# With sed
sed '0,/FROM_STRING/s//TO_STRING/' file.txt > file.txt.bak

# With python (in a custom script.py file)
for line in fileinput.input('file.txt', inplace=True):
    print line.replace(FROM_STRING, TO_STRING, 1)
    break
Run Code Online (Sandbox Code Playgroud)

一个好的观点是,FROM_STRING我正在搜索的是始终在这个巨大的1行文件的开头,前100个字符.其他好处是执行时间不是问题,可能需要时间没有问题.

编辑(解决方案):

我测试了答案的三个解决方案,所有这些都解决了问题,感谢大家.我用Linux测试了性能,time所有这些都花了大约相同的时间,大约10秒......但我选择@Miller解决方案,因为它更简单(只是使用perl).

sir*_*sen 6

由于您知道您的字符串始终位于文件的第一个块中,因此您应该使用dd此字符串.您还需要一个临时文件来处理,如tmpfile="$(mktemp)"

首先,将文件的第一个块复制到一个新的临时位置: dd bs=32k count=1 if=file.txt of="$tmpfile"

然后,在该块上进行替换: sed -i 's/FROM_STRING/TO_STRING/' "$tmpfile"

接下来,再次使用以下命令将新的第一个块与旧文件的其余部分连接起来dd: dd bs=32k if=file.txt of="$tmpfile" seek=1 skip=1


编辑:根据Mark Setchell的建议,我已经添加了bs=32k这些命令的规范,以加快dd操作的速度.根据您的需要,这是可调的,但如果明确地调整单独的命令,您可能需要注意不同输入和输出块大小之间语义的变化.

  • +1一个很好的方法,但是我可能会在开始时使用32kB,然后使用32kB块将文件重新组合在一起,因为对于更大的块,`dd`通常要快得多.具体来说,我的意思是在你的`dd`命令中添加`bs = 32k`. (2认同)