Как я могу повторить содержание файла n времена?

Я пытаюсь сравнить для сравнения двух различных способов обработать файл. У меня есть небольшое количество входных данных, но для получения хороших сравнений, я должен повторить тесты неоднократно.

Вместо того, чтобы просто повторять тесты, я хотел бы копировать входные данные неоднократно (например, 1000), таким образом, 3 файла строки становятся 3 000 строк, и я могу запустить намного больше теста выполнения.

Я передаю входные данные на пути имя файла:

mycommand input-data.txt
18
задан 8 September 2014 в 15:28

8 ответов

Вам не нужно input-duplicated.txt.

Попытка:

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

Объяснение

  • 0777 : -0 наборы устанавливают входной разделитель записей (специальная переменная жемчуга $/ который является новой строкой по умолчанию). Установка этого к значению, больше, чем 0400 заставит Perl хлебать весь входной файл в память.
  • pe : -p означает "печать каждая входная строка после применения сценария, данного -e к нему".
  • $_=$_ x 1000 : $_ текущая входная строка. Так как мы читаем весь файл сразу из-за -0700, это означает весь файл. x 1000 приведет к 1 000 копий всего распечатанного файла.
21
ответ дан 23 November 2019 в 02:05

Я первоначально думал, что должен буду генерировать вторичный файл, но я мог просто циклично выполнить исходный файл в 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 ниже и создает большой список входных имен файлов для кошки. xargs разделит это на столько аргументов, сколько система позволит. Это очень быстрее, чем , n разделяет кошек.

awk путь (вдохновленный ответ terdon ), вероятно, наиболее оптимизирован, но это копирует каждую строку за один раз. Это может или не может удовлетворить конкретному приложению, но это - молния, быстрая и эффективная.

<час>

, Но это генерирует на лету. Вывод Bash, вероятно, будет намного более медленным, чем что-то может читать, таким образом, необходимо генерировать новый файл для тестирования. К счастью это - только очень простое расширение:

(for _ in {1..1000}; do echo input-data.txt; done) | xargs cat > input-duplicated.txt
mycommand input-duplicated.txt
11
ответ дан 16 November 2019 в 12:44

Я просто использовал бы текстовый редактор.

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) заставляет энергию работать тихо, таким образом, она не должна принимать Ваше окно терминала, и -u NONE мешает ему смотреть на Ваш vimrc, который должен заставить ее работать немного быстрее, чем она иначе была бы (возможно, намного быстрее при использовании большого количества плагинов энергии).

4
ответ дан 16 November 2019 в 12:44

Вот простая острота, никакие включенные сценарии:

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

Объяснение

  • `yes input-data.txt | head -1000 | paste -s` производит текст input-data.txt 1000 раз разделенный пробелом
  • , текст затем передается cat как список файлов
4
ответ дан 16 November 2019 в 12:44

При работе над совершенно другим сценарием я узнал это с 29 миллионами строк текста, с помощью seek() и воздействуя на данные bytewise часто быстрее, чем на линию за линией основе. Та же идея применяется в сценарии ниже: мы открываем файл, и вместо цикличного выполнения посредством открытия и закрытия файла (который может добавить наверху, даже если не значительный), мы сохраняем файл, открываются и ищут назад на начало.

#!/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 текстовых файлов строки и 1 000 повторений это идет довольно хорошо, приблизительно 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() функция, которая не необходима - это - просто маленькое удобное для пользователя касание.

2
ответ дан 16 November 2019 в 12:44

Мы можем решить это без дополнительного файла, ни специальных программ, чистый Bash (хорошо, кошка является стандартной командой).

На основе функции printf в колотят, мы можем генерировать повторную строку):

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

Затем мы можем отправить такой список 1 000 (повторенных) имен файлов и назвать кошку:

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 )

Да, двойной < необходим.

1
ответ дан 16 November 2019 в 12:44

Я генерировал бы новый файл с помощью Unix для цикла:

content=$(cat Alex.pgn); for i in {1..900000}; do echo "$content" >> new_file; done 
0
ответ дан 16 November 2019 в 12:44

Вот awk решение:

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

Это по существу с такой скоростью, как Perl @Gnuc (я работал и 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
6
ответ дан 23 November 2019 в 02:05

Другие вопросы по тегам:

Похожие вопросы: