如何重复文件内容n次?

我正在尝试基准测试来比较处理文件的两种不同方式。 我有少量输入数据,但为了获得良好的比较,我需要多次重复测试。

而不是仅仅重复测试我想多次复制输入数据(例如1000),因此3行文件变为3000行,我可以运行更加充实的测试。

我通过文件名传递输入数据:

mycommand input-data.txt 

您不需要input-duplicated.txt

尝试:

 mycommand <(perl -0777pe '$_=$_ x 1000' input-data.txt) 

说明

  • 0777-0 sets设置输入记录分隔符(perl特殊变量$/默认为换行符)。 将此值设置为大于0400的值将导致Perl将整个输入文件粘贴到内存中。
  • pe -p表示“在应用-e给出的脚本后打印每个输入行”。
  • $_=$_ x 1000$_是当前输入行。 由于-0700我们一次读取整个文件,这意味着整个文件。 x 1000将导致打印整个文件的1000个副本。

我原本以为我必须生成一个辅助文件,但我可以在Bash中循环原始文件并使用一些重定向使其显示为文件。

可能有十几种不同的循环方式,但这里有四种:

 mycommand <( seq 1000 | xargs -i -- cat input-data.txt ) mycommand <( for _ in {1..1000}; do cat input-data.txt; done ) mycommand <((for _ in {1..1000}; do echo input-data.txt; done) | xargs cat ) mycommand <(awk '{for(i=0; i<1000; i++)print}' input-data.txt) #* 

第三种方法是从下面的maru评论中即兴创建的,并为cat构建一个输入文件名的大列表。 xargs会将其拆分为系统允许的参数。 它比n只独立的猫快得多。

awk方式(受到terdon答案的启发)可能是最优化的,但它一次重复每一行。 这可能适用于或不适合特定应用,但它快速而有效。


但这是在飞行中产生的。 Bash输出可能比读取的内容慢得多,因此您应该生成一个新文件进行测试。 值得庆幸的是,这只是一个非常简单的扩展:

 (for _ in {1..1000}; do echo input-data.txt; done) | xargs cat > input-duplicated.txt mycommand input-duplicated.txt 

这是一个awk解决方案:

 awk '{a[NR]=$0}END{for (i=0; i<1000; i++){for(k in a){print a[k]}}}' file 

它基本上和@ Gnuc的Perl一样快(我跑了1000次并得到了平均时间):

 $ for i in {1..1000}; do (time awk '{a[NR]=$0}END{for (i=0;i<1000;i++){for(k in a){print a[k]}}}' file > a) 2>&1 | grep -oP 'real.*?m\K[\d\.]+'; done | awk '{k+=$1}END{print k/1000}'; 0.00426 $ for i in {1..1000}; do (time perl -0777pe '$_=$_ x 1000' file > a ) 2>&1 | grep -oP 'real.*?m\K[\d\.]+'; done | awk '{k+=$1}END{print k/1000}'; 0.004076 

我只想使用文本编辑器。

 vi input-data.txt gg (move cursor to the beginning of the file) yG (yank til the end of the file) G (move the cursor to the last line of the file) 999p (paste the yanked text 999 times) :wq (save the file and exit) 

如果您绝对需要通过命令行执行此操作(这需要您安装vim ,因为vi没有:normal命令),您可以使用:

 vim -es -u NONE "+normal ggyGG999p" +wq input-data.txt 

在这里, -es (或-e -s )使vim静默运行,所以它不应该接管你的终端窗口,并且-u NONE阻止它查看你的vimrc,这应该使它运行得比它快一点会(如果你使用很多vim插件,可能会快得多)。

这是一个简单的单行程序,不涉及脚本:

 mycommand <(cat `yes input-data.txt | head -1000 | paste -s`) 

说明

  • `yes input-data.txt | head -1000 | paste -s` `yes input-data.txt | head -1000 | paste -s`生成文本input-data.txt 1000次,由空格分隔
  • 然后将文本作为文件列表传递给cat

在处理完全不同的脚本时,我了解到有2900万行文本,使用seek()并按字节顺序操作数据通常比逐行更快。 在下面的脚本中应用了相同的想法:我们打开文件,而不是循环打开和关闭文件(这可能会增加开销,即使不重要),我们保持文件打开并回头开始。

 #!/usr/bin/env python3 from __future__ import print_function import sys,os def error_out(string): sys.stderr.write(string+"\n") sys.exit(1) def read_bytewise(fp): data = fp.read(1024) print(data.decode(),end="",flush=True) while data: data = fp.read(1024) print(data.decode(),end="",flush=True) #fp.seek(0,1) def main(): howmany = int(sys.argv[1]) + 1 if not os.path.isfile(sys.argv[2]): error_out("Needs a valid file") fp = open(sys.argv[2],'rb') for i in range(1,howmany): #print(i) fp.seek(0) read_bytewise(fp) fp.close() if __name__ == '__main__': main() 

脚本本身的使用非常简单:

 ./repeat_text.py   

对于3行文本文件和1000次迭代,它很顺利,大约0.1秒:

 $ /usr/bin/time ./repeat_text.py 1000 input.txt > /dev/null 0.10user 0.00system 0:00.23elapsed 45%CPU (0avgtext+0avgdata 9172maxresident)k 0inputs+0outputs (0major+1033minor)pagefaults 0swaps 

脚本本身并不是最优雅的,可能会缩短,但可以完成工作。 当然,我在这里和那里添加了一些额外的位,比如error_out()函数,这是不必要的 – 它只是一个用户友好的小触摸。

我们可以在没有额外文件的情况下解决这个问题,也不需要特殊的程序,纯粹的Bash(嗯,cat是标准命令)。

基于bash中printf的一个特性,我们可以生成一个重复的字符串):

 printf "test.file.txt %.0s\n" {1..1000} 

然后,我们可以发送1000个文件名列表(重复)并调用cat:

 printf "test.file.txt %.0s" {1..1000} | xargs cat 

最后,我们可以将输出提供给命令来执行:

 mycommand "$( printf "%.0sinput.txt\n" {1..1000} | xargs cat )" 

或者,如果命令需要在stdin中接收输入:

 mycommand < <( printf "%.0sinput.txt\n" {1..1000} | xargs cat ) 

是的,需要双<。

我会使用Unix for循环生成一个新文件:

 content=$(cat Alex.pgn); for i in {1..900000}; do echo "$content" >> new_file; done