Я пытаюсь сравнить для сравнения двух различных способов обработать файл. У меня есть небольшое количество входных данных, но для получения хороших сравнений, я должен повторить тесты неоднократно.
Вместо того, чтобы просто повторять тесты, я хотел бы копировать входные данные неоднократно (например, 1000), таким образом, 3 файла строки становятся 3 000 строк, и я могу запустить намного больше теста выполнения.
Я передаю входные данные на пути имя файла:
mycommand input-data.txt
Вам не нужно 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 копий всего распечатанного файла. Я первоначально думал, что должен буду генерировать вторичный файл, но я мог просто циклично выполнить исходный файл в 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
Я просто использовал бы текстовый редактор.
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, который должен заставить ее работать немного быстрее, чем она иначе была бы (возможно, намного быстрее при использовании большого количества плагинов энергии).
Вот простая острота, никакие включенные сценарии:
mycommand <(cat `yes input-data.txt | head -1000 | paste -s`)
`yes input-data.txt | head -1000 | paste -s`
производит текст input-data.txt
1000 раз разделенный пробелом cat
как список файлов При работе над совершенно другим сценарием я узнал это с 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()
функция, которая не необходима - это - просто маленькое удобное для пользователя касание.
Мы можем решить это без дополнительного файла, ни специальных программ, чистый 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 )
Да, двойной < необходим.
Я генерировал бы новый файл с помощью Unix для цикла:
content=$(cat Alex.pgn); for i in {1..900000}; do echo "$content" >> new_file; done
Вот 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