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

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

Вы можете установить и запустить его так:

sudo apt-get install xbindkeys xbindkeys-config
xbindkeys-config

Инструкции здесь: http://www.nongnu.org/xbindkeys/xbindkeys.html

1
задан 8 September 2014 в 16:28

12 ответов

Я изначально думал, что мне придется создать дополнительный файл, но я мог бы просто закодировать исходный файл в 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
9
ответ дан 24 May 2018 в 03:52
  • 1
    Обе команды имеют кошку с N раз. Разве не было бы более эффективно запускать кошку один раз и кормить ее одним аргументом N раз? Что-то вроде cat $(for i in {1..N}; do echo filename; done). Это ограничивает размер arg, но должно быть быстрее. – muru 8 September 2014 в 16:33
  • 2
    @muru Хорошая идея тоже. Мне нужна была какая-то работа, но я добавлю. Текущая реализация выполняет 1000 итераций 7-строчного файла в ~ 0.020s. Это действительно намного лучше, чем мои версии, но не на уровне Perl Gnouc. – Oli♦ 8 September 2014 в 17:06

Вот решение 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
ответ дан 24 May 2018 в 03:52
  • 1
    Справедливости ради, вы могли бы, вероятно, упростить это до awk '{for(i=0; i<1000; i++)print}' input-data.txt, чтобы он просто выдавал 1000 копий каждой строки за раз. Не подходит для всех случаев, но даже быстрее, меньше задержки и не нужно хранить весь файл в ОЗУ. – Oli♦ 8 September 2014 в 20:57
  • 2
    @ Действительно, я предположил, что вы хотите сохранить порядок строк, чтобы 123123123 был в порядке, но 111222333 не был. Ваша версия явно быстрее, чем у Gnouc, она составляет 0,00297 секунд. EDIT: царапины, я сделал ошибку, это на самом деле эквивалентно в 0.004013 секунд. – terdon♦ 8 September 2014 в 21:08

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

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 doesn ' t имеет команду :normal), вы можете использовать:

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

Здесь -es (или -e -s) делает vim бесшумным, поэтому он не должен захватывать ваше окно терминала, и -u NONE останавливает его от просмотра вашего vimrc, что должно заставить его работать немного быстрее, чем в противном случае (возможно, намного быстрее, если вы используете много плагинов vim).

4
ответ дан 24 May 2018 в 03:52
  • 1
    Да, но все это руководство, которое делает его на несколько порядков медленнее и сложнее, чем другие решения. – terdon♦ 8 September 2014 в 18:37

Вот простой однострочный скрипт, никаких скриптов:

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

Объяснение

`yes input-data.txt | head -1000 | paste -s` создает текст input-data.txt 1000 раз, разделенный пробелом Текст затем передается в cat в виде списка файлов
2
ответ дан 24 May 2018 в 03:52
  • 1
    Это решение, похоже, не работает. Вам нужно использовать xargs paste -s? Это работает, но не сохраняет символы новой строки во входном файле. – JeremyKun 5 June 2016 в 06:25
  • 2
    Убедитесь, что вы используете правильный апостроф. – roeeb 6 June 2016 в 21:52

При работе с совершенно другим сценарием я узнал, что с 29 миллионами строк текста, используя 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(), что не обязательно - это просто небольшое удобное для пользователя прикосновение.

2
ответ дан 24 May 2018 в 03:52

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

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

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

Затем мы можем отправить такой список из 1000 имен файлов (повторить) и вызвать cat:

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

И, наконец, мы можем дать вывод команде execute:

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

Или, если команде необходимо получить вход в stdin:

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

Да, double & lt; необходим.

0
ответ дан 24 May 2018 в 03:52

Я бы сгенерировал новый файл, используя Unix for loop:

content=$(cat Alex.pgn); for i in {1..900000}; do echo "$content" >> new_file; done 
0
ответ дан 24 May 2018 в 03:52

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

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

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

Затем мы можем отправить такой список из 1000 имен файлов (повторить) и вызвать cat:

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

И, наконец, мы можем дать вывод команде execute:

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

Или, если команде необходимо получить вход в stdin:

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

Да, double & lt; необходим.

0
ответ дан 24 May 2018 в 03:52

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

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

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

Затем мы можем отправить такой список из 1000 имен файлов (повторить) и вызвать cat:

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

И, наконец, мы можем дать вывод команде execute:

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

Или, если команде необходимо получить вход в stdin:

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

Да, double & lt; необходим.

0
ответ дан 24 May 2018 в 03:52

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

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

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

Затем мы можем отправить такой список из 1000 имен файлов (повторить) и вызвать cat:

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

И, наконец, мы можем дать вывод команде execute:

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

Или, если команде необходимо получить вход в stdin:

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

Да, double & lt; необходим.

0
ответ дан 24 May 2018 в 03:52

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

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

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

Затем мы можем отправить такой список из 1000 имен файлов (повторить) и вызвать cat:

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

И, наконец, мы можем дать вывод команде execute:

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

Или, если команде необходимо получить вход в stdin:

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

Да, double & lt; необходим.

0
ответ дан 24 May 2018 в 03:52

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

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

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

Затем мы можем отправить такой список из 1000 имен файлов (повторить) и вызвать cat:

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

И, наконец, мы можем дать вывод команде execute:

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

Или, если команде необходимо получить вход в stdin:

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

Да, double & lt; необходим.

0
ответ дан 24 May 2018 в 03:52

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

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