我必须处理一个包含 100 万个域行的文件,调用:
1m.txt
现在我的脚本正在验证 1m.txt 中包含的行:
cat out.txt > advance.txt 2> /dev/null
cat 1m.txt | xargs -I {} -P 100 sh -c "if ! grep --quiet {} advance.txt; then if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi; fi" >> out.txt
该脚本的作用是,如果它被中断(ctrl + c)并重新启动,它将从处理的最后一行开始。如果有1000行,中断200行的进程重启很快。但是100万行,中断500k行的进程需要几个小时
有没有办法让它更有效率?
答案1
所以你当前的逻辑是“对于 1m.txt 中的每一行,查看它是否已经在 advance.txt 中。如果没有,则处理它并将其添加到 out.txt。当作业开始时,使用所有行更新 advance.txt在out.txt'中。
这样做的问题是,随着向 advance.txt 添加的行越多,每行必须比较的行就越多。最坏的情况是,如果每一行都已处理,则需要检查 1m.txt 中的每一百万行,看看它是否是 advance.txt。平均而言,您需要比较 advance.txt 中的一半行,因此这将需要 1,000,000*500,000 或 500,000,000,000(5000 亿)次比较。
如果您没有并行处理事物,则处理此问题的直接方法是找到 out.txt 中的最后一行,并跳过 1m.txt 中到该点的所有行。例如
# Pipe the output of the if/then/else/fi construct to xargs.
# use the if/then/else/fi to select the input.
# Use '-s' to see if the file exists and has non zero size.
if [ -s out.txt ] ; then
# we have some existing data
# Get the host from the last line
# delete anything that is not the last line
# remove the DIE/OK. quote anything not alphabetic with a backslash.
lasthost="$(sed '$!d;s/^\(DIE\|OK\) //;s/[^0-9a-zA-Z]/\\&/g' out.txt)"
# get the lines from 1m.txt from after the matched host
# uses GNU sed extension to start at line "0"
sed "0,/^$lasthost\$/d" 1m.txt
else
# no existing data, so just copy the 1m.txt using cat
cat 1m.txt
fi | xargs -I {} sh -c "if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi" >> out.txt
然而,您正在并行处理事物。由于host
返回值可能需要不同的时间,因此可以对输入进行显着的重新排列。需要一种更快的方法来查看主机是否已被看到。标准方法是使用某种哈希表。一种方法是使用awk
.
if [ -s out.txt ] ; then
# we have some existing data. Process the two files given
# for the first file set the entries of the seen array to 1
# for the second file print out the hosts which have not been seen.
awk 'FNR==NR {seen[$2]=1;next} seen[$1]!=1' out.txt 1m.txt
else
cat 1m.txt
fi | xargs -I {} -P 100 sh -c "if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi" >> out.txt