Как я могу случайным образом вставлять строки файла в другой текстовый файл?

#linux #bash #shell

Вопрос:

Я ищу способ случайным образом вставить все строки из одного файла в другой. Уточняя, допустим, у меня есть 2 файла:
toinsert.txt

 insert1
insert2
insert3
 

и
mainfile.txt

 line1
line2
line3
line4
line5
...
 

Результирующий файл должен выглядеть следующим образом, где строки из toinsert.txt и mainfile.txt случайным образом перепутаны:

 line1
insert1
line2
line3
insert2
...
insert3
...
 

Есть ли способ легко сделать это в bash? Ваше здоровье!

Комментарии:

1. Должны ли строки сохранять порядок?

2. @KamilCuk Не обязательно, нет. Но на самом деле это помогло бы в этом процессе.

3. Что вы пробовали? Какие исследования вы провели?

4. На самом деле я не эксперт по bash, но я знаком с Python. Это можно легко сделать, прочитав оба файла в 2 разных списка и используя random.choice() с zip() из обоих списков для создания нового списка и записи в файл. Но единственная проблема в том, что я боюсь столкнуться с проблемами с памятью.

Ответ №1:

Вы можете сделать это тривиально , используя shuf команду вместе с cat , например

 cat toinsert.txt mainfile.txt | shuf
 

Это позволит объединить строки из toinsert.txt и mainfile.txt в перетасованном порядке. Чтобы записать результат обратно mainfile.txt , вам нужно будет использовать промежуточный временный файл, например

 cat toinsert.txt mainfile.txt | shuf > tmp; mov -f tmp mainfile.txt
 

(конечно, убедитесь, что у вас еще нет tmp файла, иначе он будет перезаписан)

Дайте мне знать, если у вас возникнут дополнительные вопросы.

Комментарии:

1. Есть ли способ, которым я могу сохранить порядок? Не требуется, просто любопытно.

2. Вы можете, но это было бы немного менее эффективно. Что приходит на ум, так это использование readarray для чтения обоих файлов в отдельные массивы, затем вы можете выполнить цикл по mainfile массиву, чтобы записать случайное количество строк (например 0 , 1 , 2 ,…), а затем записать следующую строку из toinsert массива. Я уверен, что есть лучший способ сохранить порядок.

Ответ №2:

Вы в основном генерируете 3 случайных числа без повторений в диапазоне количества строк другого файла.

Нравится:

 mainfilecnt=$(wc -l <mainfile.txt)
toinsert=$(wc -l <toinsert.txt)
# copy input to output
cp mainfile.txt output.txt
# get as many random numbers as lines to insert in the range of lines
shuf -i 1-"$mainfilecnt" -n "$toinsertcnt" |
sort |
# join numbers with lines
paste - toinsert.txt |
# Reverse to insert from the last line
tac |
# we have number of line to insert to and a line.
# So insert it at that line number.
while IFS=

или как:

 # get as many random numbers as lines to insert in the range of lines
shuf -i 1-"$mainfilecnt" -n "$toinsertcnt" |
# sort reverse for inserting
sort -r |
# generate GNU sed script to insert numbers
sed 's/.*/amp;R'toinsert.txt'/' |
# Use xargs to pass generated sed script back to sed
xargs -0 -I{} sed {} mainfile.txt
 

протестировано на repl

В приведенных выше сценариях есть ошибка/особенность, из-за которой строка не будет вставлена как первая строка, только как вторая. Это всего лишь очень короткие сценарии, которые я написал, чтобы показать метод - вы должны доработать их для того, что вам действительно нужно.


t' read -r num line; do
sed -i -e "${num}i"<(printf "%sn" "$line") output.txt
done
или как:


протестировано на repl

В приведенных выше сценариях есть ошибка/особенность, из-за которой строка не будет вставлена как первая строка, только как вторая. Это всего лишь очень короткие сценарии, которые я написал, чтобы показать метод — вы должны доработать их для того, что вам действительно нужно.