Bash 优化a";“搜索和抓取”;sh脚本
这里有一个脚本,它以前工作得很好,但现在我处理的是大量inode(大约400K),它似乎会产生一些I/O慢度。 该脚本读取一个定义文件“def”,该文件是一个标识符列表,对于“dir”目录中的每个400K文件,如果在“def”特定文件末尾的前4行中找到一个标识符,则脚本将附加整个文件内容Bash 优化a";“搜索和抓取”;sh脚本,bash,loops,Bash,Loops,这里有一个脚本,它以前工作得很好,但现在我处理的是大量inode(大约400K),它似乎会产生一些I/O慢度。 该脚本读取一个定义文件“def”,该文件是一个标识符列表,对于“dir”目录中的每个400K文件,如果在“def”特定文件末尾的前4行中找到一个标识符,则脚本将附加整个文件内容 #!/bin/sh for def in *.def do touch $def.out for file in $dir/* do
#!/bin/sh
for def in *.def
do
touch $def.out
for file in $dir/*
do
if head -4 $file | grep -q -f $def
then
cat $file >> $def.out
fi
done
done
如何使其更快?Perl解决方案。它应该比脚本快得多,因为
opendir
读取目录内容。它比执行*
glob要快得多,但作为惩罚,文件没有排序。要比较您和我的脚本的输出,您必须使用
diff <(sort $def.out) <(sort $def-new.out)
更新
现在可以多次提取文件。不是创建一个巨大的正则表达式,而是创建一个正则表达式数组,并逐个进行匹配。我发现,当一个文件夹中有10000多个文件时,我开始看到一些性能问题。发生这种情况时,即使是
ls
命令也可能需要几秒钟才能返回
您的脚本似乎天生就很重。它正在查看大量文件,并创建或附加大量文件。如果不改变脚本的运行方式,我看不到任何可以改进的地方
如果可以,请将其中一些数据移动到数据库中。与文件系统相比,数据库可以更容易地调整到这种数据规模。您可以节省大量的资源;循环中保存的一个fork为整个脚本总共提供了400K个fork。这是我要做的 不要触摸每个*.def,而是大块触摸它们:
find . -name '*.def' | sed 's/\(.*\)/\1.out/' | xargs touch
(如果您的查找支持它,请使用find.-maxdepth 1
。)
在单个命令中执行此操作,而不是使用两个命令管道:
if awk "NR <= 4 && /$def/ { exit 0 } NR==5 { exit 1 }" $file; then
如果awk“NR我会尝试将dir目录中的400k分散到几个子目录中实际上,ls
命令在输入该“dir”后会遇到困难“文件夹。这个db建议是有道理的,但由于我需要每年做一次,我不确定我是否想花大量时间来赚取2天的计算机时间。谢谢你的建议。实际上,$def文件的数量大约为20,那么“触摸”步骤在我的情况下并不重要。我认为如果我可以删除一个管道(然后使用2个程序:head+grep),我确实可以改善延迟问题,但是我可能不够清楚,但是我的$def文件包含数百个“模式”,而不是像我认为您理解的那样,每个都包含一个awk命令。这就是为什么我使用grep-f
。啊,我把fgrep的-f和-f混淆了。如果输出没有排序,这并不重要。你的剧本很棒。谢谢。实际上我有个疑问。当在多个$def文件中发现公共模式时,脚本是否允许多次提取同一文件?我需要这个。@LostInTranslation:测试一下。创建简化文件,运行你的旧脚本和我的新脚本并比较结果。因此,在制作了一个玩具示例之后,我确认了这种行为。$dir中的文件不会被多次抓取,如果$def文件是文件夹中第一个列出patternA的文件,那么它将是唯一一个抓取patternA为“其名称”的所有文件的文件。我的perl技能太弱,无法找到修改的方法。我使用脚本的唯一想法是分别为每个$def文件运行它。它仍然比我以前的bash解决方案要好,但如果你有好主意,我愿意听。它只需2小时,而不是我幼稚的bash脚本中的大约15天(估计):谢谢!