Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 优化a";“搜索和抓取”;sh脚本_Bash_Loops - Fatal编程技术网

Bash 优化a";“搜索和抓取”;sh脚本

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

这里有一个脚本,它以前工作得很好,但现在我处理的是大量inode(大约400K),它似乎会产生一些I/O慢度。 该脚本读取一个定义文件“def”,该文件是一个标识符列表,对于“dir”目录中的每个400K文件,如果在“def”特定文件末尾的前4行中找到一个标识符,则脚本将附加整个文件内容

#!/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解决方案。它应该比脚本快得多,因为

  • 它从每个.def文件创建一个正则表达式。它不会多次读取每个.def文件
  • 它使用
    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天(估计):谢谢!