bash를 사용한 무작위 돌연변이

bash를 사용한 무작위 돌연변이

예를 들어 문자열이 있습니다.

1234567890

이 문자열의 임의 위치를 ​​다른 문자열 세트의 임의 순서에 있는 해당 위치로 바꾸고 싶습니다.

ABCDEFGHIJ
KLMNOPQRST
UVWXYZABCD
...

3번의 교체를 선택하면 스크립트는 3,7,8과 같은 무작위 숫자 3개와 1,1,3과 같은 3개의 무작위 시퀀스를 선택하여 예상되는 출력을 생성해야 합니다.

12C456GB90

명백한 루프 없이 이를 수행할 수 있는 방법이 있습니까? 나는 임의의 위치와 임의의 행 시퀀스를 생성한 다음 1번의 교체를 수행하고 출력에서 ​​프로세스를 반복하고 반복하고 반복하는 간단한 bash 스크립트를 작성했습니다. 이것은 잘 작동하지만 실제 파일(예제보다 훨씬 큼)에서는 10,000개 이상의 대체 항목을 생성하려고 합니다. 아, 그리고 여러 개의 "돌연변이" 변형 서열을 생성하려면 이 작업을 여러 번 수행해야 합니다.

편집: 현재 다음과 같은 것을 사용하고 있습니다.

#chose random number between 1 and the number of characters in the string
randomposition=$(jot -r 1 1 $seqpositions)
#chose a random number between 1 and the number of lines in the set of potential replacement strings
randomline=$(jot -r 1 1 $alignlines)
#find the character at randomline:randomposition
newAA=$(sed -n "$randomline,$randomline p" $alignmentfile | cut -c$randomposition)
#replace the character at 'string:randomposition' with the character at 'randomline:randomposition'
sed "s/./$newAA/$randomposition" $sequencefile

(분명히 약간의 추가 비트가 있음) 수천 번 반복합니다.

답변1

노트:

이것은 순전히 재미를 위한 것입니다. 의 동등한 프로그램은 C훨씬 더 간단하고 훨씬 더 빠릅니다. bash우리는 그것에 대해 이야기조차 하지 않습니다.

다음 perl스크립트는 내 노트북에서 약 10초 안에 약 1M 시퀀스 목록과 약 10,000개 정렬 목록을 변경합니다.

#! /usr/bin/perl
# usage mutagen number_of_replacements alignment_file [ sequence_file ..]
use strict;
my $max = shift() - 1;
my $algf = shift;
open my $alg, $algf or die "open $algf: $!";
my @alg = <$alg>;

sub prand { map int(rand() * $_[0]), 0..$max }
while(<>){
    my @ip = prand length() - 1;
    my @op = prand scalar @alg;
    for my $i (0..$max){
        my $p = $ip[$i];
        substr $_, $p, 1, substr $alg[$op[$i]], $p, 1;
    }
    print;
}

사용 예:

$ cat seq
1634870295
5684937021
2049163587
6598471230
$ cat alg
DPMBHZJEIO
INTMJZOYKQ
KNTXGLCJSR
GLJZRFVSEX
SYJVHEPNAZ
$ perl mutagen 3 alg seq
1L3V8702I5
5684HE7Y21
2049JZC587
6598H7C2E0

생성된 n난수가 달라야 하는 경우 prand다음과 같이 변경해야 합니다.

sub prand {
    my (@r, $m, %h);
    die "more replacements than positions/alignments" if $max >= $_[0];
    for(0..$max){
        my $r = int(rand() * $_[0]);
        $r = ($r + 1) % $_[0] while $h{$r};
        $h{$r} = 1;
        push @r, $r;
    }
    @r;
}

스위치가 주어졌을 때 색상의 변이를 예쁘게 인쇄하는 디버그 지원 버전 -d:

#! /usr/bin/perl
# usage mutagen [-d] number_of_replacements alignment_file [ sequence_file ..]
use strict;

my $debug = $ARGV[0] eq '-d' ? shift : 0;
my $max = shift() - 1;
my $algf = shift;
open my $alg, $algf or die "open $algf: $!";
my @alg = <$alg>;

sub prand { map int(rand() * $_[0]), 0..$max } 
while(<>){
    my @ip = prand length() - 1;
    my @op = prand scalar @alg;

    if($debug){
        my $t = ' ' x (length() - 1);
        substr $t, $ip[$_], 1, $ip[$_] for 0..$max;
        warn "@ip | @op\n    $_    $t\n";
        for my $i (0..$max){
            my $t = $alg[$op[$i]];
            $t =~ s/(.{$ip[$i]})(.)/$1\e[1;31m$2\e[m/;
            printf STDERR " %2d %s", $op[$i], $t;
        }
    }
    for my $i (0..$max){
        my $p = $ip[$i];
        substr $_, $p, 1, substr $alg[$op[$i]], $p, 1;
    }
    print;
    if($debug){
        my @t = split "", $_;
        for my $i (0..$max){
            $_ = "\e[1;31m$_\e[m" for $t[$ip[$i]];
        }
        warn "  = ", @t, "\n";
    }
}

답변2

이 선형성은 무한한 수의 임의 키를 생성합니다.

cat /dev/urandom | tr -dc 'A-Z0-9' | fold -w 10 | head -n 1

예제 출력:

MB0JZZ85VI
2OKOY4JL61
2YN7B71Z6K
KH29TYCQ4K
B4N1XOFY5O

설명하다:

/dev/random, /dev/urandom또는 /dev/arandom시스템에서 의사 난수 생성기 역할을 하는 특수 파일일 수도 있습니다. 이를 통해 장치 드라이버 및 기타 소스에서 수집된 주변 소음에 액세스할 수 있으며 더 많은 정보를 얻을 수 있습니다.여기

이것접기 명령UNIX에서 지정된 파일이나 표준 입력의 내용을 접기 위한 명령줄 유틸리티입니다. 기본적으로 최대 너비는 80열로 줄 바꿈됩니다. 또한 열 너비 지정 및 바이트 단위 줄 바꿈도 지원합니다. w명령의 플래그는 fold열 너비를 나타내며, 이는 무작위로 생성된 키에 포함된 바이트 수를 조정하는 데 간접적으로 도움이 될 수 있습니다.

명령의 정규식은 tr임의 키에 포함되는 문자를 제어합니다.

head -n생성되는 임의의 키 수를 조정합니다. 예를 들어, -n 1로 바꾸면 1000010,000개의 키가 생성됩니다.

답변3

bash실행 중인 외부 프로세스 수가 많아 초기 시도 속도가 느립니다. 모든 난수에 대해 호출되며 jot모든 문자열 연산은 two sed와 one 을 사용합니다 cut.

bash순수 대신 사용하면 sh다음과 같은 이점을 얻을 수 있습니다.$무작위바꾸다,하위 문자열 확장그리고정렬. 이를 통해 외부 명령(또는 하위 쉘) 없이도 교체를 수행할 수 있습니다 bash.

#!/bin/bash

count=$1
read sequence < $2
IFS=$'\n' read -d '' -a replacements < $3
len=${#sequence}
choices=${#replacements[*]}

while ((count--)) ; do
        pos=$(($RANDOM % $len))
        choice=$(($RANDOM % $choices))
        replacement=${replacements[$choice]}
        sequence=${sequence:0:$pos}${replacement:$pos:1}${sequence:$((pos+1))}
done

echo "$sequence"

$RANDOM은 32767을 초과하지 않으므로 시퀀스가 ​​그보다 크거나 해당 크기에 가까운 경우 이를 $RANDOM % maximum.

컴파일된 언어는 물론, 전용 스크립팅 언어를 속도 면에서 능가하는 것은 여전히 ​​불가능합니다.

관련 정보