Настроить:
У меня 50 файлов, каждая из которых содержит 25000 строк.
Делать:
Мне нужно перетасовать все их "в том же порядке". Например:
Если перед перемещением:
File 1 File 2 File 3
A A A
B B B
C C C
то после перетасовки я должен получить:
File 1 File 2 File 3
B B B
C C C
A A A
т.е. соответствующие строки в файлах следует перетасовывать в том же порядке.
Кроме того, перетасовка должна быть детерминированной, т.е. Если я даю файл A в качестве входного сигнала, он должен всегда производить такой же перетасованный вывод.
Я могу написать программу Java, чтобы сделать это, возможно, сценарий. Что-то вроде, перетасовать число от 1 до 25000 и сохранить это в файле, скажем, shuffle_order. Затем просто обрабатывайте один файл и заказывайте существующие строки в соответствии с shuffle_order. Но есть ли лучший/быстрый способ сделать это?
Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.
В следующем используются только базовые команды bash. Принцип:
код
#!/bin/bash
case "$#" in
0) echo "Usage: $0 files....." ; exit 1;;
esac
ORDER="./.rand.$$"
trap "rm -f $ORDER;exit" 1 2
count=$(grep -c '^' "$1")
let odcount=$(($count * 4))
paste -d" " <(od -A n -N $odcount -t u4 /dev/urandom | grep -o '[0-9]*') <(seq -w $count) |\
sort -k1n | cut -d " " -f2 > $ORDER
#if your system has the "shuf" command you can replace the above 3 lines with a simple
#seq -w $count | shuf > $ORDER
for file in "$@"
do
paste -d' ' $ORDER $file | sort -k1n | cut -d' ' -f2- > "$file.rand"
done
echo "the order is in the file $ORDER" # remove this line
#rm -f $ORDER # and uncomment this
# if dont need preserve the order
paste -d " " *.rand #remove this line - it is only for showing test result
из входных файлов:
A B C
--------
a1 a2 a3
b1 b2 b3
c1 c2 c3
d1 d2 d3
e1 e2 e3
f1 f2 f3
g1 g2 g3
h1 h2 h3
i1 i2 i3
j1 j2 j3
сделает A.rand B.rand C.rand
следующим примером контента
g1 g2 g3
e1 e2 e3
b1 b2 b3
c1 c2 c3
f1 f2 f3
j1 j2 j3
d1 d2 d3
h1 h2 h3
i1 i2 i3
a1 a2 a3
реальное тестирование - создание 50 файлов с 25k строк
line="Consequatur qui et qui. Mollitia expedita aut excepturi modi. Enim nihil et laboriosam sit a tenetur."
for n in $(seq -w 50)
do
seq -f "$line %g" 25000 >file.$n
done
запуск скрипта
bash sorter.sh file.??
результат на моей записной книжке
real 1m13.404s
user 0m56.127s
sys 0m5.143s
Вероятно, очень неэффективно, но попробуйте ниже:
#!/bin/bash
arr=( $(for i in {1..25000}; do
echo "$i"
done | shuf) )
for file in files*; do
index=0
new=$(while read line; do
echo "${arr[$index]} $line"
(( index++ ))
done < "$file" | sort -h | sed 's/^[0-9]\+ //')
echo "$new" > "$file"
done