我想在 > 2GB 的文本文件中搜索和替换超过 6000 个字符串。
sed -i "s/search/replace/g" 2gbfile.log
需要很长时间。特别是如果你必须做 6000 次以上。
因此我想出了一个脚本,将 2 GB 的文件拆分成多个块,以便我可以并行处理。我同时运行 48 个进程(64 个可用核心),但仍然需要很长时间。
#!/usr/bin/env bash
echo "sorting..."
sort bigbigbigfile | awk -F, '{print $2,$1,$3}' > bigbigbigfile.work
CPUS=$(( $(lscpu |grep "On-line CPU(s) list"|grep -Eo '0-[0-9]+'|cut -f2 -d-) + 1))
CPUSUSABLE=$(echo "$CPUS*0.75" | bc | cut -f1 -d.)
NUMLINES=$(cat all-temperatures.sort | wc -l)
SPLIT=$(echo "$NUMLINES / $CPUSUSABLE" | bc | cut -f1 -d.)
echo "cutting..."
split -l $SPLIT bigbigbigfile.work chunkstoworkwith
mapfile -t REPLACEME < replace.list
echo "seding..."
for chunk in $(ls chunkstoworkwith*); do
(
for i in "${!REPLACEME[@]}"; do
counter=$(( counter + 1 ))
sed -i "s/ ${REPLACEME[$i]} / $counter /g" $chunk
done
) &
done
这有效。但我认为在内存中搜索和替换可能会更快,而不是使用 sed 就地替换并在 48 个文件中执行 6000 多次替换。这总计近 30 万次 sed 调用,这会导致大量文件打开/关闭/写入/等等。
关于如何加快速度并在内存中进行替换以及在所有内容更改后清除数据,有什么想法吗?
答案1
您的脚本正在解析每个替换的整个块!
这意味着对于每个块,脚本都会打开,遍历所有行,可能执行 1 次替换,关闭文件并将其移动到原始文件(由于选项-i
)。
假设您想用计数数字替换模式,这里有一种方法可以立即对每个块执行所有替换:
sed -f <(awk '{print "s/ "$1" / "++c" /"}' replace.list) -i "$chunk"
该-f
选项允许将 sed 脚本作为输入,并将立即对文件的所有行执行$chunk
。
这可能会减少总体时间......
答案2
我不完全确定为什么你的 sed 运行得这么慢,你可能需要调试或仔细观察才能真正发现,但如果它试图写入 6,000 次并且这减慢了它的速度,你可以跳过-i
并让 sed 将整个(更改的)文件写出一次:
sed "s/search/replace/g" 2gbfile.log > 2bgfile-AfterSed.log