나는 데이터 목록을 가지고있다.
12345
23456
67891
-20000
200
600
20
...
이 데이터 세트의 크기 (즉, 파일 라인)가이라고 가정하십시오 N
. m
이 데이터 파일에서 무작위로 선을 그리고 싶습니다 . 따라서 출력은 두 개의 파일이어야합니다. 하나는 이러한 m
데이터 라인을 포함하는 파일 이고 다른 하나는 N-m
데이터 라인을 포함 합니다.
Linux 명령을 사용하여이를 수행 할 수있는 방법이 있습니까?
답변
이것은 가장 효율적인 방법은 아니지만 작동합니다.
shuf <file> > tmp
head -n $m tmp > out1
tail -n +$(( m + 1 )) tmp > out2
와 $m
라인의 수를 포함.
답변
이 bash / awk 스크립트는 무작위로 행을 선택하고 두 출력 파일 모두에서 원래 순서를 유지합니다.
awk -v m=4 -v N=$(wc -l <file) -v out1=/tmp/out1 -v out2=/tmp/out2 \
'BEGIN{ srand()
do{ lnb = 1 + int(rand()*N)
if ( !(lnb in R) ) {
R[lnb] = 1
ct++ }
} while (ct<m)
} { if (R[NR]==1) print > out1
else print > out2
}' file
cat /tmp/out1
echo ========
cat /tmp/out2
질문의 데이터를 기반으로하는 출력입니다.
12345
23456
200
600
========
67891
-20000
20
답변
모든 유닉스와 마찬가지로 해당 TM에 대한 유틸리티가 있습니다 .
오늘의 프로그램 : split
split
파일을 여러 가지 방법으로 -b
바이트, -l
줄, -n
출력 파일 수로 나눕니다 . 우리는 -l
옵션을 사용할 것입니다. 당신은 첫 번째 무작위 라인과하지를 선택하려는 때문에 m
, 우리는거야 sort
무작위로 파일을 처음. 에 대해 읽으려면 여기sort
에서 내 대답을 참조 하십시오 .
이제 실제 코드입니다. 정말 간단합니다.
sort -R input_file | split -l $m output_prefix
이 두 개의 파일을 하나 만들 것입니다 m
라인과 하나의 N-m
선, 이름 output_prefixaa
등을 output_prefixab
. m
더 큰 파일을 원하는지 확인하십시오. 그렇지 않으면 길이가 여러 개인 파일을 얻을 수 있습니다 m
(하나는 N % m
).
올바른 크기를 사용하려면 다음을 수행하는 작은 코드가 있습니다.
m=10 # size you want one file to be
N=$(wc -l input_file)
m=$(( m > N/2 ? m : N - m ))
sort -R input_file | split -l $m output_prefix
편집 : 일부 sort
구현에는 -R
플래그 가 없다는 것이 주목되었습니다 . 당신이 가진 경우에 perl
, 당신은 대신 할 수 있습니다 perl -e 'use List::Util qw/shuffle/; print shuffle <>;'
.
답변
줄 순서를 바꾸지 않아도되고 GNU coreutils가있는 경우 (즉, shuf
버전 6.0에 등장한 이후로 너무 오래되지 않은 내장되지 않은 Linux 또는 Cygwin )shuf
(“셔플”)은 파일의 줄을 무작위로 다시 정렬합니다. 따라서 파일을 섞어서 첫 번째 m 행을 한 파일로, 나머지 m 행을 다른 파일로 발송할 수 있습니다.
그 파견을 수행하는 이상적인 방법은 없습니다. 당신은 체인을 할 수 없습니다 head
하고 tail
있기 때문에 head
앞으로 버퍼 것입니다. 을 사용할 수 split
있지만 출력 파일 이름과 관련하여 유연성을 얻지 못합니다. awk
물론 사용할 수 있습니다 :
<input shuf | awk -v m=$m '{ if (NR <= m) {print >"output1"} else {print} }'
을 사용할 수 있습니다 sed
.이 기능은 애매하지만 큰 파일에는 더 빠릅니다.
<input shuf | sed -e "1,${m} w output1" -e "1,${m} d" >output2
또는 tee
플랫폼에 데이터가있는 경우 데이터를 복제하는 데 사용할 수 있습니다 /dev/fd
. m이 작 으면 괜찮습니다.
<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2
awk를 사용하여 각 줄을 차례로 전달할 수 있습니다. awk는 난수 생성기를 초기화하는 데별로 좋지 않습니다. 무작위성은 암호화에 적합하지 않을뿐만 아니라 수치 시뮬레이션에도 적합하지 않습니다. 시드는 1 초의 기간이있는 시스템에서 모든 awk 호출에 대해 동일합니다.
<input awk -v N=$(wc -l <input) -v m=3 '
BEGIN {srand()}
{
if (rand() * N < m) {--m; print >"output1"} else {print >"output2"}
--N;
}'
더 나은 무작위성이 필요한 경우 Perl에서 동일한 작업을 수행하여 RNG를 적절하게 시드 할 수 있습니다.
<input perl -e '
open OUT1, ">", "output1" or die $!;
open OUT2, ">", "output2" or die $!;
my $N = `wc -l <input`;
my $m = $ARGV[0];
while (<STDIN>) {
if (rand($N) < $m) { --$m; print OUT1 $_; } else { print OUT2 $_; }
--$N;
}
close OUT1 or die $!;
close OUT2 or die $!;
' 42
답변
가정 m = 7
및 N = 21
:
cp ints ints.bak
for i in {1..7}
do
rnd=$((RANDOM%(21-i)+1))
# echo $rnd;
sed -n "${rnd}{p,q}" 10k.dat >> mlines
sed -i "${rnd}d" ints
done
참고 : 교체하는 경우 7
와 같은 변수 $1
또는 $m
, 당신은 사용할 필요가 seq
아닌 {from..to}
변수 확장을하지 않는 표기법을.
파일에서 줄 단위로 삭제하여 짧아지고 짧아 지므로 제거 할 수있는 줄 번호가 점점 작아야합니다.