回答:
必要ありませんinput-duplicated.txt
。
試してください:
mycommand <(perl -0777pe '$_=$_ x 1000' input-data.txt)
0777
:-0
setsは、入力レコードの区切り文字($/
デフォルトでは改行であるperl特殊変数)を設定します。これをより大きな値に設定すると、0400
Perlは入力ファイル全体をメモリに丸lurみします。pe
:は、-p
「与えられたスクリプトを適用した後に各入力行を印刷する」という意味-e
です。$_=$_ x 1000
:$_
現在の入力行です。のためにファイル全体を一度に読んでいるので-0700
、これはファイル全体を意味します。これx 1000
により、ファイル全体の1000コピーが印刷されます。perl
は非常に効率的であり、このために設計されています。
元々、セカンダリファイルを生成する必要があると考えていましたが、元のファイルをBashでループして、リダイレクトを使用してファイルとして表示することができました。
ループを実行する方法はおそらく12種類ありますが、次の4つがあります。
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) #*
3番目の方法は、以下の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
cat $(for i in {1..N}; do echo filename; done)
。これにはargサイズの制限がありますが、もっと速いはずです。
ここだ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
awk '{for(i=0; i<1000; i++)print}' input-data.txt
して、一度に各行のコピーを1000個だけ発行することができます。すべての状況に適しているわけではありませんが、より高速で遅延が少なく、ファイル全体をRAMに保持する必要はありません。
123123123
はうまくいった111222333
がそうではなかった。お使いのバージョンは、Gnoucのバージョンよりも明らかに高速で、平均は0.00297秒です。編集:スクラッチ、私は間違いを犯した、それは実際には0.004013秒で同等です。
テキストエディタを使用するだけです。
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`
input-data.txt
空白で区切られたテキストを1000回生成しますcat
ファイルリストとして渡されますxargs paste -s
か?これは機能しますが、入力ファイルの改行を保持しません。
完全に異なるスクリプトで作業している間、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 <INT> <TEXT.txt>
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 )"
または、コマンドが標準入力で入力を受信する必要がある場合:
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