【问题标题】:bash: how to copy multiple copies of one file into another fast?bash:如何将一个文件的多个副本快速复制到另一个文件中?
【发布时间】:2015-10-12 18:11:41
【问题描述】:

我需要通过向程序提供越来越大的输入文件来对程序进行压力测试。我有一个输入文件inputSmall.txt,我想将N 次和cat 复制到同一个文件中。 N 是大文件。如果有任何比以下简单循环更快的方法(例如N=1000):

for i in {1..1000}
do 
    cat inputSmall.txt >> input1000.txt
done

我的机器有足够的磁盘空间来存储inputN.txt 非常大的Ns,并且有很多内存,以防相关。

谢谢

【问题讨论】:

  • for i in {1..1000}; do cat inputSmall.txt; done >> input1000.txt 理论上可能更快,但我不知道它在实践中是否有所作为。
  • cat inputSmall.txt{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,} >> inputNN.txt 有效,但需要正确数量的逗号。您可以生成大括号字符串,但是您需要使用eval cat inputSmall.txt{$commavar} 来执行它,这并不令人愉快。
  • for ((i=0; i<1000; i++)); do printf '%s\0' inputSmall.txt; done | xargs -0 cat >input1000.txt 是另一种小/最小的方法,至少最小化cat 调用的次数和打开输出文件的次数(但不会最小化输入文件的打开次数)重读)。

标签: bash cat replicate


【解决方案1】:

cat 是一个外部命令,而不是 shell 的一部分;像所有外部命令一样,启动它有很大的开销。同样,运行>>input1000.txt 是一项相当昂贵的文件系统操作——查找与目录关联的inode,将其打开,然后(在离开范围时)刷新内容并关闭文件。

这些事情只做一次效率更高。


假设inputSmall.txt 的最后一行以换行符结束,以下将正常工作,并且开销要少得多:

in=$(<inputSmall.txt)        # read the input file only once
exec 3>>input1000.txt        # open the output file only once

for ((i=0; i<1000; i++)); do
  printf '%s\n' "$in" >&3    # write the input from memory to the output fd
done
exec 3>&-                    # close the output fd

【讨论】:

    【解决方案2】:

    当你写作时

    for i in {1..1000}
    

    您告诉外壳程序首先将 1 到 1000 的所有数字写入命令缓冲区,然后遍历每个数字。对于大数字,这不仅速度很慢,而且 bur 还增加了显着的内存需求(例如,参见 unix.se 上的 this post)。

    在 bash 中,您可以使用以下语法来避免这一切:

    for ((i=1; i<=1000;i++))
    

    作为奖励,这允许边界是变量。

    【讨论】:

    • 确实如此,但与每次循环迭代重新打开输出文件一次相比,它的开销要小得多。
    【解决方案3】:

    这样您可以更快地完成“指数”,但您需要为 tmp 文件留出一些额外的磁盘空间。

    input=$1
    
    new=${input}.new.txt
    tmp=${input}.tmp.txt
    
    cat ${input} > ${new}
    cat "" > ${tmp}
    
    # 2^10=1024
    for ((i=0; i<10 ; i++))
    do
            cat ${new} >> ${tmp}
            cat ${tmp} >> ${new}
    done
    
    rm ${tmp}
    

    【讨论】:

    • 每一个都被截断,这意味着你得到的结果与原始代码截然不同。
    • 如果文件需要多次写入调用,这仍然是一个非常不同的结果:您可以将内容交错。它还在地板上留下了许多潜在的性能增强:您开始 cat 1000 次,读取输入文件 1000 次,打开输出文件 1000 次,等等。
    • 再次更新,但没有针对 100MB+ 的大文件进行测试,您没有定义“大”的含义:)
    • 在这种情况下,“大”意味着多个写入块。这通常不会超过 8kb,可能小到 512 字节,具体取决于运行时平台的详细信息。
    • 顺便说一句,每次运行 &gt;&gt; ${new} 时,都会重新打开输出文件——因此,需要付出性能代价。
    猜你喜欢
    • 2014-12-05
    • 1970-01-01
    • 2017-03-01
    • 1970-01-01
    • 2013-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多